diff mbox

[Fortran,pr60322] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array

Message ID 20150324180620.3c72960e@vepi2
State New
Headers show

Commit Message

Andre Vehreschild March 24, 2015, 5:06 p.m. UTC
Hi all,

I have worked on the comments Mikael gave me. I am now checking for
class_pointer in the way he pointed out.

Furthermore did I *join the two parts* of the patch into this one, because
keeping both in sync was no benefit but only tedious and did not prove to be
reviewed faster.

Paul, Dominique: I have addressed the LOC issue that came up lately. Or rather
the patch addressed it already. I feel like this is not tested very well, not
the loc() call nor the sizeof() call as given in the 57305 second's download.
Unfortunately, is that download not runable. I would love to see a test similar
to that download, but couldn't come up with one, that satisfied me. Given that
the patch's review will last some days, I still have enough time to come up
with something beautiful which I will add then.

Bootstraps and regtests ok on x86_64-linux-gnu/F20.

Regards,
	Andre


On Tue, 24 Mar 2015 11:13:27 +0100
Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote:

> Dear Andre,
> 
> Dominique pointed out to me that the 'loc' patch causes a ICE in the
> testsuite. It seems that 'loc' should provide the address of the class
> container in some places and the address of the data in others. I will
> put my thinking cap on tonight :-)
> 
> Cheers
> 
> Paul
> 
> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote:
> > Hi Mikael,
> >
> > thanks for looking at the patch. Please note, that Paul has sent an
> > addendum to the patches for 60322, which I deliberately have attached.
> >
> >>  26/02/2015 18:17, Andre Vehreschild a écrit :
> >> > This first patch is only preparatory and does not change any of the
> >> > semantics of gfortran at all.
> >> Sure?
> >
> > With the counterexample you found below, this of course is a wrong
> > statement.
> >
> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
> >> > index ab6f7a5..d28cf77 100644
> >> > --- a/gcc/fortran/expr.c
> >> > +++ b/gcc/fortran/expr.c
> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym)
> >> >    lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name);
> >> >
> >> >    /* It will always be a full array.  */
> >> > -  lval->rank = sym->as ? sym->as->rank : 0;
> >> > +  as = sym->as;
> >> > +  lval->rank = as ? as->rank : 0;
> >> >    if (lval->rank)
> >> > -    gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ?
> >> > -                       CLASS_DATA (sym)->as : sym->as);
> >> > +    gfc_add_full_array_ref (lval, as);
> >>
> >> This is a change of semantics.  Or do you know that sym->ts.type !=
> >> BT_CLASS?
> >
> > You are completely right. I have made a mistake here. I have to tell the
> > truth, I never ran a regtest with only part 1 of the patches applied. The
> > second part of the patch will correct this, by setting the variable as
> > depending on whether type == BT_CLASS or not. Sorry for the mistake.
> >
> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
> >> > index 3664824..e571a17 100644
> >> > --- a/gcc/fortran/trans-decl.c
> >> > +++ b/gcc/fortran/trans-decl.c
> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym,
> >> > tree dummy) tree decl;
> >> >    tree type;
> >> >    gfc_array_spec *as;
> >> > +  symbol_attribute *array_attr;
> >> >    char *name;
> >> >    gfc_packed packed;
> >> >    int n;
> >> >    bool known_size;
> >> >
> >> > -  if (sym->attr.pointer || sym->attr.allocatable
> >> > -      || (sym->as && sym->as->type == AS_ASSUMED_RANK))
> >> > +  /* Use the array as and attr.  */
> >> > +  as = sym->as;
> >> > +  array_attr = &sym->attr;
> >> > +
> >> > +  /* The pointer attribute is always set on a _data component, therefore
> >> > check
> >> > +     the sym's attribute only.  */
> >> > +  if (sym->attr.pointer || array_attr->allocatable
> >> > +      || (as && as->type == AS_ASSUMED_RANK))
> >> >      return dummy;
> >> >
> >> Any reason to sometimes use array_attr, sometimes not, like here?
> >> By the way, the comment is misleading: for classes, there is the
> >> class_pointer attribute (and it is a pain, I know).
> >
> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes
> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later
> > case .pointer is always set to 1 in the _data component's attr. I.e., the
> > above if, would always yield true for a class_array, which is not intended,
> > but rather destructive. I know about the class_pointer attribute, but I
> > figured, that it is not relevant here. Any idea how to formulate the
> > comment better, to reflect what I just explained?
> >
> > Regards,
> >         Andre
> > --
> > Andre Vehreschild * Email: vehre ad gmx dot de
> >
> >
> > ---------- Forwarded message ----------
> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com>
> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres
> > <dominiq@lps.ens.fr> Cc:
> > Date: Sun, 22 Mar 2015 21:20:20 +0100
> > Subject: Bug in intrinsic LOC for scalar class objects
> > Dear Andre and Dominique,
> >
> > I have found that LOC is returning the address of the class container
> > rather than the _data component for class scalars. See the source
> > below, which you will recognise! A fix is attached.
> >
> > Note that the scalar allocate fails with MOLD= and so I substituted SOURCE=.
> >
> > Cheers
> >
> > Paul
> >
> >     class(*), allocatable :: a(:), e ! Change 'e' to an array and
> > second memcpy works correctly
> >                                      ! Problem is with loc(e), which
> > returns the address of the
> >                                      ! class container.
> >     allocate (e, source = 99.0)
> >     allocate (a(2), source = [1.0, 2.0])
> >     call add_element_poly (a,e)
> >     select type (a)
> >       type is (real)
> >         print *, a
> >     end select
> >
> > contains
> >
> >     subroutine add_element_poly(a,e)
> >       use iso_c_binding
> >       class(*),allocatable,intent(inout),target :: a(:)
> >       class(*),intent(in),target :: e
> >       class(*),allocatable,target :: tmp(:)
> >       type(c_ptr) :: dummy
> >
> >       interface
> >         function memcpy(dest,src,n) bind(C,name="memcpy") result(res)
> >           import
> >           type(c_ptr) :: res
> >           integer(c_intptr_t),value :: dest
> >           integer(c_intptr_t),value :: src
> >           integer(c_size_t),value :: n
> >         end function
> >       end interface
> >
> >       if (.not.allocated(a)) then
> >         allocate(a(1), source=e)
> >       else
> >         allocate(tmp(size(a)),source=a)
> >         deallocate(a)
> >         allocate(a(size(tmp)+1),source=e) ! mold gives a segfault
> >         dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp))
> >         dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e))
> >       end if
> >     end subroutine
> > end
> >
> 
> 
>

Comments

Dominique d'Humières March 25, 2015, 9:43 a.m. UTC | #1
Hi Andre,

> Le 24 mars 2015 à 18:06, Andre Vehreschild <vehre@gmx.de> a écrit :
> 
> Hi all,
> 
> I have worked on the comments Mikael gave me. I am now checking for
> class_pointer in the way he pointed out.
> 
> Furthermore did I *join the two parts* of the patch into this one, because
> keeping both in sync was no benefit but only tedious and did not prove to be
> reviewed faster.

Are you sure that you attached the right patch? It does not apply on a clean tree unless I apply the patch at

https://gcc.gnu.org/ml/fortran/2015-02/msg00105.html

with minor surgery for gcc/fortran/expr.c.

> Paul, Dominique: I have addressed the LOC issue that came up lately. Or rather
> the patch addressed it already. I feel like this is not tested very well, not
> the loc() call nor the sizeof() call as given in the 57305 second's download.

The ICE is fixed and the LOC issue seems fixed. 

> Unfortunately, is that download not runable. I would love to see a test similar
> to that download, but couldn't come up with one, that satisfied me. Given that
> the patch's review will last some days, I still have enough time to come up
> with something beautiful which I will add then.

I have changed the test to

use iso_c_binding
implicit none
real, target :: e
class(*), allocatable, target :: a(:)
e = 1.0
call add_element_poly(a,e)
print *, size(a)
call add_element_poly(a,e)
print *, size(a)
select type (a)
  type is (real)
    print *, a
end select
contains
    subroutine add_element_poly(a,e)
      use iso_c_binding
      class(*),allocatable,intent(inout),target :: a(:)
      class(*),intent(in),target :: e
      class(*),allocatable,target :: tmp(:)
      type(c_ptr) :: dummy
      
      interface
        function memcpy(dest,src,n) bind(C,name="memcpy") result(res)
          import
          type(c_ptr) :: res
          integer(c_intptr_t),value :: dest
          integer(c_intptr_t),value :: src
          integer(c_size_t),value :: n
        end function
      end interface

      if (.not.allocated(a)) then
        allocate(a(1), source=e)
      else
        print *, size(a)
        allocate(tmp(size(a)),source=a)
        print *, size(a), size(tmp) + 1
        print *, loc(a(1)),loc(tmp),sizeof(tmp)
        deallocate(a)
!        allocate(a(size(tmp)+1),mold=e)
        allocate(a(size(tmp)+1),source=e)
        print *, size(a), size(tmp)
        dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp))
        dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e))
      end if
    end subroutine
end

As pointed by Paul, I get a segfault at run time if I use the commented line, i.e. ‘mold’ instead of ‘source’.

> Bootstraps and regtests ok on x86_64-linux-gnu/F20.
> 
> Regards,
> 	Andre

Thanks for your work.

Dominique
Paul Richard Thomas March 27, 2015, 12:48 p.m. UTC | #2
Dear Andre,

I am in the UK as of last night. Before leaving, I bootstrapped and
regtested your patch and all was well. I must drive to Cambridge this
afternoon to see my mother and will try to get to it either this
evening or tomorrow morning. There is so much of it and it touches
many places; so I must give it a very careful looking over before
giving the green light. Bear with me please.

Great work though!

Paul

On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote:
> Hi all,
>
> I have worked on the comments Mikael gave me. I am now checking for
> class_pointer in the way he pointed out.
>
> Furthermore did I *join the two parts* of the patch into this one, because
> keeping both in sync was no benefit but only tedious and did not prove to be
> reviewed faster.
>
> Paul, Dominique: I have addressed the LOC issue that came up lately. Or rather
> the patch addressed it already. I feel like this is not tested very well, not
> the loc() call nor the sizeof() call as given in the 57305 second's download.
> Unfortunately, is that download not runable. I would love to see a test similar
> to that download, but couldn't come up with one, that satisfied me. Given that
> the patch's review will last some days, I still have enough time to come up
> with something beautiful which I will add then.
>
> Bootstraps and regtests ok on x86_64-linux-gnu/F20.
>
> Regards,
>         Andre
>
>
> On Tue, 24 Mar 2015 11:13:27 +0100
> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote:
>
>> Dear Andre,
>>
>> Dominique pointed out to me that the 'loc' patch causes a ICE in the
>> testsuite. It seems that 'loc' should provide the address of the class
>> container in some places and the address of the data in others. I will
>> put my thinking cap on tonight :-)
>>
>> Cheers
>>
>> Paul
>>
>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote:
>> > Hi Mikael,
>> >
>> > thanks for looking at the patch. Please note, that Paul has sent an
>> > addendum to the patches for 60322, which I deliberately have attached.
>> >
>> >>  26/02/2015 18:17, Andre Vehreschild a écrit :
>> >> > This first patch is only preparatory and does not change any of the
>> >> > semantics of gfortran at all.
>> >> Sure?
>> >
>> > With the counterexample you found below, this of course is a wrong
>> > statement.
>> >
>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
>> >> > index ab6f7a5..d28cf77 100644
>> >> > --- a/gcc/fortran/expr.c
>> >> > +++ b/gcc/fortran/expr.c
>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym)
>> >> >    lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name);
>> >> >
>> >> >    /* It will always be a full array.  */
>> >> > -  lval->rank = sym->as ? sym->as->rank : 0;
>> >> > +  as = sym->as;
>> >> > +  lval->rank = as ? as->rank : 0;
>> >> >    if (lval->rank)
>> >> > -    gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ?
>> >> > -                       CLASS_DATA (sym)->as : sym->as);
>> >> > +    gfc_add_full_array_ref (lval, as);
>> >>
>> >> This is a change of semantics.  Or do you know that sym->ts.type !=
>> >> BT_CLASS?
>> >
>> > You are completely right. I have made a mistake here. I have to tell the
>> > truth, I never ran a regtest with only part 1 of the patches applied. The
>> > second part of the patch will correct this, by setting the variable as
>> > depending on whether type == BT_CLASS or not. Sorry for the mistake.
>> >
>> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
>> >> > index 3664824..e571a17 100644
>> >> > --- a/gcc/fortran/trans-decl.c
>> >> > +++ b/gcc/fortran/trans-decl.c
>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym,
>> >> > tree dummy) tree decl;
>> >> >    tree type;
>> >> >    gfc_array_spec *as;
>> >> > +  symbol_attribute *array_attr;
>> >> >    char *name;
>> >> >    gfc_packed packed;
>> >> >    int n;
>> >> >    bool known_size;
>> >> >
>> >> > -  if (sym->attr.pointer || sym->attr.allocatable
>> >> > -      || (sym->as && sym->as->type == AS_ASSUMED_RANK))
>> >> > +  /* Use the array as and attr.  */
>> >> > +  as = sym->as;
>> >> > +  array_attr = &sym->attr;
>> >> > +
>> >> > +  /* The pointer attribute is always set on a _data component, therefore
>> >> > check
>> >> > +     the sym's attribute only.  */
>> >> > +  if (sym->attr.pointer || array_attr->allocatable
>> >> > +      || (as && as->type == AS_ASSUMED_RANK))
>> >> >      return dummy;
>> >> >
>> >> Any reason to sometimes use array_attr, sometimes not, like here?
>> >> By the way, the comment is misleading: for classes, there is the
>> >> class_pointer attribute (and it is a pain, I know).
>> >
>> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes
>> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later
>> > case .pointer is always set to 1 in the _data component's attr. I.e., the
>> > above if, would always yield true for a class_array, which is not intended,
>> > but rather destructive. I know about the class_pointer attribute, but I
>> > figured, that it is not relevant here. Any idea how to formulate the
>> > comment better, to reflect what I just explained?
>> >
>> > Regards,
>> >         Andre
>> > --
>> > Andre Vehreschild * Email: vehre ad gmx dot de
>> >
>> >
>> > ---------- Forwarded message ----------
>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com>
>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres
>> > <dominiq@lps.ens.fr> Cc:
>> > Date: Sun, 22 Mar 2015 21:20:20 +0100
>> > Subject: Bug in intrinsic LOC for scalar class objects
>> > Dear Andre and Dominique,
>> >
>> > I have found that LOC is returning the address of the class container
>> > rather than the _data component for class scalars. See the source
>> > below, which you will recognise! A fix is attached.
>> >
>> > Note that the scalar allocate fails with MOLD= and so I substituted SOURCE=.
>> >
>> > Cheers
>> >
>> > Paul
>> >
>> >     class(*), allocatable :: a(:), e ! Change 'e' to an array and
>> > second memcpy works correctly
>> >                                      ! Problem is with loc(e), which
>> > returns the address of the
>> >                                      ! class container.
>> >     allocate (e, source = 99.0)
>> >     allocate (a(2), source = [1.0, 2.0])
>> >     call add_element_poly (a,e)
>> >     select type (a)
>> >       type is (real)
>> >         print *, a
>> >     end select
>> >
>> > contains
>> >
>> >     subroutine add_element_poly(a,e)
>> >       use iso_c_binding
>> >       class(*),allocatable,intent(inout),target :: a(:)
>> >       class(*),intent(in),target :: e
>> >       class(*),allocatable,target :: tmp(:)
>> >       type(c_ptr) :: dummy
>> >
>> >       interface
>> >         function memcpy(dest,src,n) bind(C,name="memcpy") result(res)
>> >           import
>> >           type(c_ptr) :: res
>> >           integer(c_intptr_t),value :: dest
>> >           integer(c_intptr_t),value :: src
>> >           integer(c_size_t),value :: n
>> >         end function
>> >       end interface
>> >
>> >       if (.not.allocated(a)) then
>> >         allocate(a(1), source=e)
>> >       else
>> >         allocate(tmp(size(a)),source=a)
>> >         deallocate(a)
>> >         allocate(a(size(tmp)+1),source=e) ! mold gives a segfault
>> >         dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp))
>> >         dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e))
>> >       end if
>> >     end subroutine
>> > end
>> >
>>
>>
>>
>
>
> --
> Andre Vehreschild * Email: vehre ad gmx dot de
Paul Richard Thomas April 5, 2015, 9:13 a.m. UTC | #3
Dear Andre,

Well, time passed and it didn't get done. Too much going on at the moment!

As you say, the patch bootstraps and regtests on x86_64, FC21 in my case.

I am now very reluctant to mess around with the gcc-5 release. Thus, I
think that this patch must be committed to 5.2 and 6.0, when the are
open for business.

A few trivial comments:

+  /* The dummy is returned for pointer, allocatable or assumed rank arrays.
+     The check for pointerness needs to be repeated here (it is done in
+     IS_CLASS_ARRAY (), too), because for class arrays that are pointers, as
+     is the one of the sym, which is incorrect here.  */

What does this mean, please?

+      /* Returning the descriptor for dummy class arrays is hazardous, because
+     some caller is expecting an expression to apply the component refs to.
+     Therefore the descriptor is only created and stored in
+     sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR.  The caller is then
+     responsible to extract it from there, when the descriptor is
+     desired.  */
+      if (IS_CLASS_ARRAY (sym)
+      && (!DECL_LANG_SPECIFIC (sym->backend_decl)
+          || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl)))
+    {
+      decl = gfc_build_dummy_array_decl (sym, sym->backend_decl);
+      /* Prevent the dummy from being detected as unused if it is copied.  */
+      if (sym->backend_decl != NULL && decl != sym->backend_decl)
+        DECL_ARTIFICIAL (sym->backend_decl) = 1;
+      sym->backend_decl = decl;
+    }

The comments, such as the above are often going well beyond column 72,
into the 80's. I know that much of the existing code violates this
style requirement but there is no need to do so if clarity is not
reduced thereby.

In trans-stmt.c s/standart/standard/

Don't forget to put the PR numbers in the ChangeLogs.

For this submission, I would have appreciated some a description of
what each chunk in the patch is doing, just because there is so much
of it. I suppose that it was good for my imortal soul to sort it out
for myself but it took a little while :-)

Cheers and many thanks for the patch.

Paul

On 27 March 2015 at 13:48, Paul Richard Thomas
<paul.richard.thomas@gmail.com> wrote:
> Dear Andre,
>
> I am in the UK as of last night. Before leaving, I bootstrapped and
> regtested your patch and all was well. I must drive to Cambridge this
> afternoon to see my mother and will try to get to it either this
> evening or tomorrow morning. There is so much of it and it touches
> many places; so I must give it a very careful looking over before
> giving the green light. Bear with me please.
>
> Great work though!
>
> Paul
>
> On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote:
>> Hi all,
>>
>> I have worked on the comments Mikael gave me. I am now checking for
>> class_pointer in the way he pointed out.
>>
>> Furthermore did I *join the two parts* of the patch into this one, because
>> keeping both in sync was no benefit but only tedious and did not prove to be
>> reviewed faster.
>>
>> Paul, Dominique: I have addressed the LOC issue that came up lately. Or rather
>> the patch addressed it already. I feel like this is not tested very well, not
>> the loc() call nor the sizeof() call as given in the 57305 second's download.
>> Unfortunately, is that download not runable. I would love to see a test similar
>> to that download, but couldn't come up with one, that satisfied me. Given that
>> the patch's review will last some days, I still have enough time to come up
>> with something beautiful which I will add then.
>>
>> Bootstraps and regtests ok on x86_64-linux-gnu/F20.
>>
>> Regards,
>>         Andre
>>
>>
>> On Tue, 24 Mar 2015 11:13:27 +0100
>> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote:
>>
>>> Dear Andre,
>>>
>>> Dominique pointed out to me that the 'loc' patch causes a ICE in the
>>> testsuite. It seems that 'loc' should provide the address of the class
>>> container in some places and the address of the data in others. I will
>>> put my thinking cap on tonight :-)
>>>
>>> Cheers
>>>
>>> Paul
>>>
>>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote:
>>> > Hi Mikael,
>>> >
>>> > thanks for looking at the patch. Please note, that Paul has sent an
>>> > addendum to the patches for 60322, which I deliberately have attached.
>>> >
>>> >>  26/02/2015 18:17, Andre Vehreschild a écrit :
>>> >> > This first patch is only preparatory and does not change any of the
>>> >> > semantics of gfortran at all.
>>> >> Sure?
>>> >
>>> > With the counterexample you found below, this of course is a wrong
>>> > statement.
>>> >
>>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
>>> >> > index ab6f7a5..d28cf77 100644
>>> >> > --- a/gcc/fortran/expr.c
>>> >> > +++ b/gcc/fortran/expr.c
>>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym)
>>> >> >    lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name);
>>> >> >
>>> >> >    /* It will always be a full array.  */
>>> >> > -  lval->rank = sym->as ? sym->as->rank : 0;
>>> >> > +  as = sym->as;
>>> >> > +  lval->rank = as ? as->rank : 0;
>>> >> >    if (lval->rank)
>>> >> > -    gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ?
>>> >> > -                       CLASS_DATA (sym)->as : sym->as);
>>> >> > +    gfc_add_full_array_ref (lval, as);
>>> >>
>>> >> This is a change of semantics.  Or do you know that sym->ts.type !=
>>> >> BT_CLASS?
>>> >
>>> > You are completely right. I have made a mistake here. I have to tell the
>>> > truth, I never ran a regtest with only part 1 of the patches applied. The
>>> > second part of the patch will correct this, by setting the variable as
>>> > depending on whether type == BT_CLASS or not. Sorry for the mistake.
>>> >
>>> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
>>> >> > index 3664824..e571a17 100644
>>> >> > --- a/gcc/fortran/trans-decl.c
>>> >> > +++ b/gcc/fortran/trans-decl.c
>>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym,
>>> >> > tree dummy) tree decl;
>>> >> >    tree type;
>>> >> >    gfc_array_spec *as;
>>> >> > +  symbol_attribute *array_attr;
>>> >> >    char *name;
>>> >> >    gfc_packed packed;
>>> >> >    int n;
>>> >> >    bool known_size;
>>> >> >
>>> >> > -  if (sym->attr.pointer || sym->attr.allocatable
>>> >> > -      || (sym->as && sym->as->type == AS_ASSUMED_RANK))
>>> >> > +  /* Use the array as and attr.  */
>>> >> > +  as = sym->as;
>>> >> > +  array_attr = &sym->attr;
>>> >> > +
>>> >> > +  /* The pointer attribute is always set on a _data component, therefore
>>> >> > check
>>> >> > +     the sym's attribute only.  */
>>> >> > +  if (sym->attr.pointer || array_attr->allocatable
>>> >> > +      || (as && as->type == AS_ASSUMED_RANK))
>>> >> >      return dummy;
>>> >> >
>>> >> Any reason to sometimes use array_attr, sometimes not, like here?
>>> >> By the way, the comment is misleading: for classes, there is the
>>> >> class_pointer attribute (and it is a pain, I know).
>>> >
>>> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes
>>> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later
>>> > case .pointer is always set to 1 in the _data component's attr. I.e., the
>>> > above if, would always yield true for a class_array, which is not intended,
>>> > but rather destructive. I know about the class_pointer attribute, but I
>>> > figured, that it is not relevant here. Any idea how to formulate the
>>> > comment better, to reflect what I just explained?
>>> >
>>> > Regards,
>>> >         Andre
>>> > --
>>> > Andre Vehreschild * Email: vehre ad gmx dot de
>>> >
>>> >
>>> > ---------- Forwarded message ----------
>>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com>
>>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres
>>> > <dominiq@lps.ens.fr> Cc:
>>> > Date: Sun, 22 Mar 2015 21:20:20 +0100
>>> > Subject: Bug in intrinsic LOC for scalar class objects
>>> > Dear Andre and Dominique,
>>> >
>>> > I have found that LOC is returning the address of the class container
>>> > rather than the _data component for class scalars. See the source
>>> > below, which you will recognise! A fix is attached.
>>> >
>>> > Note that the scalar allocate fails with MOLD= and so I substituted SOURCE=.
>>> >
>>> > Cheers
>>> >
>>> > Paul
>>> >
>>> >     class(*), allocatable :: a(:), e ! Change 'e' to an array and
>>> > second memcpy works correctly
>>> >                                      ! Problem is with loc(e), which
>>> > returns the address of the
>>> >                                      ! class container.
>>> >     allocate (e, source = 99.0)
>>> >     allocate (a(2), source = [1.0, 2.0])
>>> >     call add_element_poly (a,e)
>>> >     select type (a)
>>> >       type is (real)
>>> >         print *, a
>>> >     end select
>>> >
>>> > contains
>>> >
>>> >     subroutine add_element_poly(a,e)
>>> >       use iso_c_binding
>>> >       class(*),allocatable,intent(inout),target :: a(:)
>>> >       class(*),intent(in),target :: e
>>> >       class(*),allocatable,target :: tmp(:)
>>> >       type(c_ptr) :: dummy
>>> >
>>> >       interface
>>> >         function memcpy(dest,src,n) bind(C,name="memcpy") result(res)
>>> >           import
>>> >           type(c_ptr) :: res
>>> >           integer(c_intptr_t),value :: dest
>>> >           integer(c_intptr_t),value :: src
>>> >           integer(c_size_t),value :: n
>>> >         end function
>>> >       end interface
>>> >
>>> >       if (.not.allocated(a)) then
>>> >         allocate(a(1), source=e)
>>> >       else
>>> >         allocate(tmp(size(a)),source=a)
>>> >         deallocate(a)
>>> >         allocate(a(size(tmp)+1),source=e) ! mold gives a segfault
>>> >         dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp))
>>> >         dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e))
>>> >       end if
>>> >     end subroutine
>>> > end
>>> >
>>>
>>>
>>>
>>
>>
>> --
>> Andre Vehreschild * Email: vehre ad gmx dot de
>
>
>
> --
> Outside of a dog, a book is a man's best friend. Inside of a dog it's
> too dark to read.
>
> Groucho Marx
Andre Vehreschild April 9, 2015, 12:37 p.m. UTC | #4
Hi Paul, hi all,

Paul, thanks for the review. Answers to your questions are inline below:

On Sun, 5 Apr 2015 11:13:05 +0200
Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote:
<snip>
> +  /* The dummy is returned for pointer, allocatable or assumed rank arrays.
> +     The check for pointerness needs to be repeated here (it is done in
> +     IS_CLASS_ARRAY (), too), because for class arrays that are pointers, as
> +     is the one of the sym, which is incorrect here.  */
> 
> What does this mean, please?

The first sentence is about regular arrays and should be unchanged from the
original source. Then I have to check for class (arrays) that are pointers,
i.e., independent of whether the sym is a class array or a regular pointer to a
class object. (The latter shouldn't make it into the routine anyway.)
IS_CLASS_ARRAY () returns false for too many reasons to be of use here. I have
to apologize and confess that the comment was a mere note to myself to not
return to use is_classarray in the if below. Let me rephrase the comment to be:

/* The dummy is returned for pointer, allocatable or assumed rank arrays.
   For class arrays the information if sym is an allocatable or pointer
   object needs to be checked explicitly (IS_CLASS_ARRAY can be false for
   too many reasons to be of use here).  */

> +      /* Returning the descriptor for dummy class arrays is hazardous,
> because
> +     some caller is expecting an expression to apply the component refs to.
> +     Therefore the descriptor is only created and stored in
> +     sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR.  The caller is then
> +     responsible to extract it from there, when the descriptor is
> +     desired.  */
> +      if (IS_CLASS_ARRAY (sym)
> +      && (!DECL_LANG_SPECIFIC (sym->backend_decl)
> +          || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl)))
> +    {
> +      decl = gfc_build_dummy_array_decl (sym, sym->backend_decl);
> +      /* Prevent the dummy from being detected as unused if it is copied.  */
> +      if (sym->backend_decl != NULL && decl != sym->backend_decl)
> +        DECL_ARTIFICIAL (sym->backend_decl) = 1;
> +      sym->backend_decl = decl;
> +    }
> 
> The comments, such as the above are often going well beyond column 72,
> into the 80's. I know that much of the existing code violates this
> style requirement but there is no need to do so if clarity is not
> reduced thereby.

Er, the document at 

https://gcc.gnu.org/codingconventions.html#C_Formatting 

says that line length is 80, or is there another convention, that I am not
aware of?

> In trans-stmt.c s/standart/standard/

Fixed.

> Don't forget to put the PR numbers in the ChangeLogs.

I won't anymore, already got told off :-)

> For this submission, I would have appreciated some a description of
> what each chunk in the patch is doing, just because there is so much
> of it. I suppose that it was good for my imortal soul to sort it out
> for myself but it took a little while :-)

I initially tried to split the submission in two parts to make it more
manageable. One part with the brain-dead substitutions of as and array_attr and
one with the new code. Albeit I failed to get the brain-dead part right and
made some mistakes there already, which Mikael pointed out. I therefore went
for the big submission. 

Now doing a description of what each "chunk" does is quite tedious. I really
would like to spend my time more productive. Would you be satisfied, when I
write a story about the patch, referring to some parts more explicitly, like

"Chunk 4 of file trans-stmt.c is the heart of the patch and does this and that.
The remaining chunks are more or less putting the data together."

(This is not correct for this patch of course. Just an example.) More elaborate
of course, but just to give an idea.

Thanks again. I will commit as soon as 5.2/6.0 commit window is open.

Regards,
	Andre

> 
> Cheers and many thanks for the patch.
> 
> Paul
> 
> On 27 March 2015 at 13:48, Paul Richard Thomas
> <paul.richard.thomas@gmail.com> wrote:
> > Dear Andre,
> >
> > I am in the UK as of last night. Before leaving, I bootstrapped and
> > regtested your patch and all was well. I must drive to Cambridge this
> > afternoon to see my mother and will try to get to it either this
> > evening or tomorrow morning. There is so much of it and it touches
> > many places; so I must give it a very careful looking over before
> > giving the green light. Bear with me please.
> >
> > Great work though!
> >
> > Paul
> >
> > On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote:
> >> Hi all,
> >>
> >> I have worked on the comments Mikael gave me. I am now checking for
> >> class_pointer in the way he pointed out.
> >>
> >> Furthermore did I *join the two parts* of the patch into this one, because
> >> keeping both in sync was no benefit but only tedious and did not prove to
> >> be reviewed faster.
> >>
> >> Paul, Dominique: I have addressed the LOC issue that came up lately. Or
> >> rather the patch addressed it already. I feel like this is not tested very
> >> well, not the loc() call nor the sizeof() call as given in the 57305
> >> second's download. Unfortunately, is that download not runable. I would
> >> love to see a test similar to that download, but couldn't come up with
> >> one, that satisfied me. Given that the patch's review will last some days,
> >> I still have enough time to come up with something beautiful which I will
> >> add then.
> >>
> >> Bootstraps and regtests ok on x86_64-linux-gnu/F20.
> >>
> >> Regards,
> >>         Andre
> >>
> >>
> >> On Tue, 24 Mar 2015 11:13:27 +0100
> >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote:
> >>
> >>> Dear Andre,
> >>>
> >>> Dominique pointed out to me that the 'loc' patch causes a ICE in the
> >>> testsuite. It seems that 'loc' should provide the address of the class
> >>> container in some places and the address of the data in others. I will
> >>> put my thinking cap on tonight :-)
> >>>
> >>> Cheers
> >>>
> >>> Paul
> >>>
> >>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote:
> >>> > Hi Mikael,
> >>> >
> >>> > thanks for looking at the patch. Please note, that Paul has sent an
> >>> > addendum to the patches for 60322, which I deliberately have attached.
> >>> >
> >>> >>  26/02/2015 18:17, Andre Vehreschild a écrit :
> >>> >> > This first patch is only preparatory and does not change any of the
> >>> >> > semantics of gfortran at all.
> >>> >> Sure?
> >>> >
> >>> > With the counterexample you found below, this of course is a wrong
> >>> > statement.
> >>> >
> >>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
> >>> >> > index ab6f7a5..d28cf77 100644
> >>> >> > --- a/gcc/fortran/expr.c
> >>> >> > +++ b/gcc/fortran/expr.c
> >>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym)
> >>> >> >    lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name);
> >>> >> >
> >>> >> >    /* It will always be a full array.  */
> >>> >> > -  lval->rank = sym->as ? sym->as->rank : 0;
> >>> >> > +  as = sym->as;
> >>> >> > +  lval->rank = as ? as->rank : 0;
> >>> >> >    if (lval->rank)
> >>> >> > -    gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ?
> >>> >> > -                       CLASS_DATA (sym)->as : sym->as);
> >>> >> > +    gfc_add_full_array_ref (lval, as);
> >>> >>
> >>> >> This is a change of semantics.  Or do you know that sym->ts.type !=
> >>> >> BT_CLASS?
> >>> >
> >>> > You are completely right. I have made a mistake here. I have to tell the
> >>> > truth, I never ran a regtest with only part 1 of the patches applied.
> >>> > The second part of the patch will correct this, by setting the variable
> >>> > as depending on whether type == BT_CLASS or not. Sorry for the mistake.
> >>> >
> >>> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
> >>> >> > index 3664824..e571a17 100644
> >>> >> > --- a/gcc/fortran/trans-decl.c
> >>> >> > +++ b/gcc/fortran/trans-decl.c
> >>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym,
> >>> >> > tree dummy) tree decl;
> >>> >> >    tree type;
> >>> >> >    gfc_array_spec *as;
> >>> >> > +  symbol_attribute *array_attr;
> >>> >> >    char *name;
> >>> >> >    gfc_packed packed;
> >>> >> >    int n;
> >>> >> >    bool known_size;
> >>> >> >
> >>> >> > -  if (sym->attr.pointer || sym->attr.allocatable
> >>> >> > -      || (sym->as && sym->as->type == AS_ASSUMED_RANK))
> >>> >> > +  /* Use the array as and attr.  */
> >>> >> > +  as = sym->as;
> >>> >> > +  array_attr = &sym->attr;
> >>> >> > +
> >>> >> > +  /* The pointer attribute is always set on a _data component,
> >>> >> > therefore check
> >>> >> > +     the sym's attribute only.  */
> >>> >> > +  if (sym->attr.pointer || array_attr->allocatable
> >>> >> > +      || (as && as->type == AS_ASSUMED_RANK))
> >>> >> >      return dummy;
> >>> >> >
> >>> >> Any reason to sometimes use array_attr, sometimes not, like here?
> >>> >> By the way, the comment is misleading: for classes, there is the
> >>> >> class_pointer attribute (and it is a pain, I know).
> >>> >
> >>> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes
> >>> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the
> >>> > later case .pointer is always set to 1 in the _data component's attr.
> >>> > I.e., the above if, would always yield true for a class_array, which is
> >>> > not intended, but rather destructive. I know about the class_pointer
> >>> > attribute, but I figured, that it is not relevant here. Any idea how to
> >>> > formulate the comment better, to reflect what I just explained?
> >>> >
> >>> > Regards,
> >>> >         Andre
> >>> > --
> >>> > Andre Vehreschild * Email: vehre ad gmx dot de
> >>> >
> >>> >
> >>> > ---------- Forwarded message ----------
> >>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com>
> >>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres
> >>> > <dominiq@lps.ens.fr> Cc:
> >>> > Date: Sun, 22 Mar 2015 21:20:20 +0100
> >>> > Subject: Bug in intrinsic LOC for scalar class objects
> >>> > Dear Andre and Dominique,
> >>> >
> >>> > I have found that LOC is returning the address of the class container
> >>> > rather than the _data component for class scalars. See the source
> >>> > below, which you will recognise! A fix is attached.
> >>> >
> >>> > Note that the scalar allocate fails with MOLD= and so I substituted
> >>> > SOURCE=.
> >>> >
> >>> > Cheers
> >>> >
> >>> > Paul
> >>> >
> >>> >     class(*), allocatable :: a(:), e ! Change 'e' to an array and
> >>> > second memcpy works correctly
> >>> >                                      ! Problem is with loc(e), which
> >>> > returns the address of the
> >>> >                                      ! class container.
> >>> >     allocate (e, source = 99.0)
> >>> >     allocate (a(2), source = [1.0, 2.0])
> >>> >     call add_element_poly (a,e)
> >>> >     select type (a)
> >>> >       type is (real)
> >>> >         print *, a
> >>> >     end select
> >>> >
> >>> > contains
> >>> >
> >>> >     subroutine add_element_poly(a,e)
> >>> >       use iso_c_binding
> >>> >       class(*),allocatable,intent(inout),target :: a(:)
> >>> >       class(*),intent(in),target :: e
> >>> >       class(*),allocatable,target :: tmp(:)
> >>> >       type(c_ptr) :: dummy
> >>> >
> >>> >       interface
> >>> >         function memcpy(dest,src,n) bind(C,name="memcpy") result(res)
> >>> >           import
> >>> >           type(c_ptr) :: res
> >>> >           integer(c_intptr_t),value :: dest
> >>> >           integer(c_intptr_t),value :: src
> >>> >           integer(c_size_t),value :: n
> >>> >         end function
> >>> >       end interface
> >>> >
> >>> >       if (.not.allocated(a)) then
> >>> >         allocate(a(1), source=e)
> >>> >       else
> >>> >         allocate(tmp(size(a)),source=a)
> >>> >         deallocate(a)
> >>> >         allocate(a(size(tmp)+1),source=e) ! mold gives a segfault
> >>> >         dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp))
> >>> >         dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e))
> >>> >       end if
> >>> >     end subroutine
> >>> > end
> >>> >
> >>>
> >>>
> >>>
> >>
> >>
> >> --
> >> Andre Vehreschild * Email: vehre ad gmx dot de
> >
> >
> >
> > --
> > Outside of a dog, a book is a man's best friend. Inside of a dog it's
> > too dark to read.
> >
> > Groucho Marx
> 
> 
>
diff mbox

Patch

diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index 65495d2..7f3a59d 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -4060,7 +4060,7 @@  gfc_lval_expr_from_sym (gfc_symbol *sym)
   lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name);
 
   /* It will always be a full array.  */
-  as = sym->ts.type == BT_CLASS ? CLASS_DATA (sym)->as : sym->as;
+  as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as;
   lval->rank = as ? as->rank : 0;
   if (lval->rank)
     gfc_add_full_array_ref (lval, as);
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 8e6595f..901a1c0 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3206,6 +3206,11 @@  bool gfc_is_finalizable (gfc_symbol *, gfc_expr **);
 	 && CLASS_DATA (sym) \
 	 && CLASS_DATA (sym)->ts.u.derived \
 	 && CLASS_DATA (sym)->ts.u.derived->attr.unlimited_polymorphic)
+#define IS_CLASS_ARRAY(sym) \
+	(sym->ts.type == BT_CLASS \
+	 && CLASS_DATA (sym) \
+	 && CLASS_DATA (sym)->attr.dimension \
+	 && !CLASS_DATA (sym)->attr.class_pointer)
 
 /* frontend-passes.c */
 
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index afe73a9..0804d45 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -2495,11 +2495,14 @@  gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
 	case GFC_SS_REFERENCE:
 	  /* Scalar argument to elemental procedure.  */
 	  gfc_init_se (&se, NULL);
-	  if (ss_info->can_be_null_ref)
+	  if (ss_info->can_be_null_ref || (expr->symtree
+			     && (expr->symtree->n.sym->ts.type == BT_DERIVED
+				 || expr->symtree->n.sym->ts.type == BT_CLASS)))
 	    {
 	      /* If the actual argument can be absent (in other words, it can
 		 be a NULL reference), don't try to evaluate it; pass instead
-		 the reference directly.  */
+		 the reference directly.  The reference is also needed when
+		 expr is of type class or derived.  */
 	      gfc_conv_expr_reference (&se, expr);
 	    }
 	  else
@@ -3046,7 +3049,14 @@  build_class_array_ref (gfc_se *se, tree base, tree index)
 	return false;
     }
   else if (class_ref == NULL)
-    decl = expr->symtree->n.sym->backend_decl;
+    {
+      decl = expr->symtree->n.sym->backend_decl;
+      /* For class arrays the tree containing the class is stored in
+	 GFC_DECL_SAVED_DESCRIPTOR of the sym's backend_decl.
+	 For all others it's sym's backend_decl directly.  */
+      if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl))
+	decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
+    }
   else
     {
       /* Remove everything after the last class reference, convert the
@@ -3159,26 +3169,41 @@  build_array_ref (tree desc, tree offset, tree decl)
 {
   tree tmp;
   tree type;
+  tree cdecl;
+  bool classarray = false;
+
+  /* For class arrays the class declaration is stored in the saved
+     descriptor.  */
+  if (INDIRECT_REF_P (desc)
+      && DECL_LANG_SPECIFIC (TREE_OPERAND (desc, 0))
+      && GFC_DECL_SAVED_DESCRIPTOR (TREE_OPERAND (desc, 0)))
+    cdecl = gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR (
+				  TREE_OPERAND (desc, 0)));
+  else
+    cdecl = desc;
 
   /* Class container types do not always have the GFC_CLASS_TYPE_P
      but the canonical type does.  */
-  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))
-      && TREE_CODE (desc) == COMPONENT_REF)
+  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (cdecl))
+      && TREE_CODE (cdecl) == COMPONENT_REF)
     {
-      type = TREE_TYPE (TREE_OPERAND (desc, 0));
+      type = TREE_TYPE (TREE_OPERAND (cdecl, 0));
       if (TYPE_CANONICAL (type)
 	  && GFC_CLASS_TYPE_P (TYPE_CANONICAL (type)))
-	type = TYPE_CANONICAL (type);
+	{
+	  type = TREE_TYPE (desc);
+	  classarray = true;
+	}
     }
   else
     type = NULL;
 
   /* Class array references need special treatment because the assigned
      type size needs to be used to point to the element.  */
-  if (type && GFC_CLASS_TYPE_P (type))
+  if (classarray)
     {
-      type = gfc_get_element_type (TREE_TYPE (desc));
-      tmp = TREE_OPERAND (desc, 0);
+      type = gfc_get_element_type (type);
+      tmp = TREE_OPERAND (cdecl, 0);
       tmp = gfc_get_class_array_ref (offset, tmp);
       tmp = fold_convert (build_pointer_type (type), tmp);
       tmp = build_fold_indirect_ref_loc (input_location, tmp);
@@ -5570,7 +5595,7 @@  gfc_trans_array_cobounds (tree type, stmtblock_t * pblock,
   gfc_se se;
   gfc_array_spec *as;
 
-  as = sym->as;
+  as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as;
 
   for (dim = as->rank; dim < as->rank + as->corank; dim++)
     {
@@ -5613,7 +5638,7 @@  gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset,
 
   int dim;
 
-  as = sym->as;
+  as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as;
 
   size = gfc_index_one_node;
   offset = gfc_index_zero_node;
@@ -5901,12 +5926,16 @@  gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc,
   int no_repack;
   bool optional_arg;
   gfc_array_spec *as;
+  bool is_classarray = IS_CLASS_ARRAY (sym);
 
   /* Do nothing for pointer and allocatable arrays.  */
-  if (sym->attr.pointer || sym->attr.allocatable)
+  if ((sym->ts.type != BT_CLASS && sym->attr.pointer)
+      || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer)
+      || sym->attr.allocatable
+      || (is_classarray && CLASS_DATA (sym)->attr.allocatable))
     return;
 
-  if (sym->attr.dummy && gfc_is_nodesc_array (sym))
+  if (!is_classarray && sym->attr.dummy && gfc_is_nodesc_array (sym))
     {
       gfc_trans_g77_array (sym, block);
       return;
@@ -5919,8 +5948,13 @@  gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc,
   type = TREE_TYPE (tmpdesc);
   gcc_assert (GFC_ARRAY_TYPE_P (type));
   dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc);
-  dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc);
-  as = sym->as;
+  if (is_classarray)
+    /* For a class array the dummy array descriptor is in the _class
+       component.  */
+    dumdesc = gfc_class_data_get (dumdesc);
+  else
+    dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc);
+  as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as;
   gfc_start_block (&init);
 
   if (sym->ts.type == BT_CHARACTER
@@ -6791,6 +6825,7 @@  gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
       tree from;
       tree to;
       tree base;
+      bool onebased = false;
 
       ndim = info->ref ? info->ref->u.ar.dimen : ss->dimen;
 
@@ -6932,6 +6967,7 @@  gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
 				    gfc_array_index_type, to, tmp);
 	      from = gfc_index_one_node;
 	    }
+	  onebased = integer_onep (from);
 	  gfc_conv_descriptor_lbound_set (&loop.pre, parm,
 					  gfc_rank_cst[dim], from);
 
@@ -6988,13 +7024,27 @@  gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
 	gfc_get_dataptr_offset (&loop.pre, parm, desc, offset,
 				subref_array_target, expr);
 
-      if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc)))
-	   && !se->data_not_needed)
-	  || (se->use_offset && base != NULL_TREE))
+      /* Force the offset to be -1, when the lower bound of the highest
+	 dimension is one and the symbol is present and is not a
+	 pointer/allocatable or associated.  */
+      if (onebased && se->use_offset
+	  && expr->symtree
+	  && !expr->symtree->n.sym->attr.allocatable
+	  && !expr->symtree->n.sym->attr.pointer
+	  && !expr->symtree->n.sym->attr.host_assoc
+	  && !expr->symtree->n.sym->attr.use_assoc)
 	{
-	  /* Set the offset.  */
-	  gfc_conv_descriptor_offset_set (&loop.pre, parm, base);
+	  /* Set the offset to -1.  */
+	  mpz_t minus_one;
+	  mpz_init_set_si (minus_one, -1);
+	  tmp = gfc_conv_mpz_to_tree (minus_one, gfc_index_integer_kind);
+	  gfc_conv_descriptor_offset_set (&loop.pre, parm, tmp);
 	}
+      else if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc)))
+		&& !se->data_not_needed)
+	       || (se->use_offset && base != NULL_TREE))
+	/* Set the offset depending on base.  */
+	gfc_conv_descriptor_offset_set (&loop.pre, parm, base);
       else
 	{
 	  /* Only the callee knows what the correct offset it, so just set
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index d3fcdd1..895733b 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -814,10 +814,11 @@  gfc_build_qualified_array (tree decl, gfc_symbol * sym)
   gfc_namespace* procns;
   symbol_attribute *array_attr;
   gfc_array_spec *as;
+  bool is_classarray = IS_CLASS_ARRAY (sym);
 
   type = TREE_TYPE (decl);
-  array_attr = &sym->attr;
-  as = sym->as;
+  array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr;
+  as = is_classarray ? CLASS_DATA (sym)->as : sym->as;
 
   /* We just use the descriptor, if there is one.  */
   if (GFC_DESCRIPTOR_TYPE_P (type))
@@ -1023,14 +1024,19 @@  gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy)
   gfc_packed packed;
   int n;
   bool known_size;
+  bool is_classarray = IS_CLASS_ARRAY (sym);
 
   /* Use the array as and attr.  */
-  as = sym->as;
-  array_attr = &sym->attr;
-
-  /* The pointer attribute is always set on a _data component, therefore check
-     the sym's attribute only.  */
-  if (sym->attr.pointer || array_attr->allocatable
+  as = is_classarray ? CLASS_DATA (sym)->as : sym->as;
+  array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr;
+
+  /* The dummy is returned for pointer, allocatable or assumed rank arrays.
+     The check for pointerness needs to be repeated here (it is done in
+     IS_CLASS_ARRAY (), too), because for class arrays that are pointers, as
+     is the one of the sym, which is incorrect here.  */
+  if ((sym->ts.type != BT_CLASS && sym->attr.pointer)
+      || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer)
+      || array_attr->allocatable
       || (as && as->type == AS_ASSUMED_RANK))
     return dummy;
 
@@ -1039,24 +1045,27 @@  gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy)
   if (sym->attr.result || sym->attr.dummy)
     gfc_defer_symbol_init (sym);
 
-  type = TREE_TYPE (dummy);
+  /* For a class array the array descriptor is in the _data component, while
+     for a regular array the TREE_TYPE of the dummy is a pointer to the
+     descriptor.  */
+  type = TREE_TYPE (is_classarray ? gfc_class_data_get (dummy)
+				  : TREE_TYPE (dummy));
+  /* type now is the array descriptor w/o any indirection.  */
   gcc_assert (TREE_CODE (dummy) == PARM_DECL
-	  && POINTER_TYPE_P (type));
+	  && POINTER_TYPE_P (TREE_TYPE (dummy)));
 
   /* Do we know the element size?  */
   known_size = sym->ts.type != BT_CHARACTER
 	  || INTEGER_CST_P (sym->ts.u.cl->backend_decl);
 
-  if (known_size && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type)))
+  if (known_size && !GFC_DESCRIPTOR_TYPE_P (type))
     {
       /* For descriptorless arrays with known element size the actual
          argument is sufficient.  */
-      gcc_assert (GFC_ARRAY_TYPE_P (type));
       gfc_build_qualified_array (dummy, sym);
       return dummy;
     }
 
-  type = TREE_TYPE (type);
   if (GFC_DESCRIPTOR_TYPE_P (type))
     {
       /* Create a descriptorless array pointer.  */
@@ -1090,7 +1099,10 @@  gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy)
 	    packed = PACKED_PARTIAL;
 	}
 
-      type = gfc_typenode_for_spec (&sym->ts);
+      /* For classarrays the element type is required, but
+	 gfc_typenode_for_spec () returns the array descriptor.  */
+      type = is_classarray ? gfc_get_element_type (type)
+			   : gfc_typenode_for_spec (&sym->ts);
       type = gfc_get_nodesc_array_type (type, as, packed,
 					!sym->attr.target);
     }
@@ -1440,13 +1452,30 @@  gfc_get_symbol_decl (gfc_symbol * sym)
 	  sym->backend_decl = decl;
 	}
 
+      /* Returning the descriptor for dummy class arrays is hazardous, because
+	 some caller is expecting an expression to apply the component refs to.
+	 Therefore the descriptor is only created and stored in
+	 sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR.  The caller is then
+	 responsible to extract it from there, when the descriptor is
+	 desired.  */
+      if (IS_CLASS_ARRAY (sym)
+	  && (!DECL_LANG_SPECIFIC (sym->backend_decl)
+	      || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl)))
+	{
+	  decl = gfc_build_dummy_array_decl (sym, sym->backend_decl);
+	  /* Prevent the dummy from being detected as unused if it is copied.  */
+	  if (sym->backend_decl != NULL && decl != sym->backend_decl)
+	    DECL_ARTIFICIAL (sym->backend_decl) = 1;
+	  sym->backend_decl = decl;
+	}
+
       TREE_USED (sym->backend_decl) = 1;
       if (sym->attr.assign && GFC_DECL_ASSIGN (sym->backend_decl) == 0)
 	{
 	  gfc_add_assign_aux_vars (sym);
 	}
 
-      if (sym->attr.dimension
+      if ((sym->attr.dimension || IS_CLASS_ARRAY (sym))
 	  && DECL_LANG_SPECIFIC (sym->backend_decl)
 	  && GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl)
 	  && DECL_CONTEXT (sym->backend_decl) != current_function_decl)
@@ -3987,14 +4016,16 @@  gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 		= gfc_class_set_static_fields (sym->backend_decl, vptr, tmp);
 	  TREE_CONSTANT (DECL_INITIAL (sym->backend_decl)) = 1;
 	}
-      else if (sym->attr.dimension || sym->attr.codimension)
+      else if (sym->attr.dimension || sym->attr.codimension
+	       || (IS_CLASS_ARRAY (sym) && !CLASS_DATA (sym)->attr.allocatable))
 	{
+	  bool is_classarray = IS_CLASS_ARRAY (sym);
 	  symbol_attribute *array_attr;
 	  gfc_array_spec *as;
 	  array_type tmp;
 
-	  array_attr = &sym->attr;
-	  as = sym->as;
+	  array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr;
+	  as = is_classarray ? CLASS_DATA (sym)->as : sym->as;
 	  /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT.  */
 	  tmp = as->type;
 	  if (tmp == AS_ASSUMED_SIZE && as->cp_was_assumed)
@@ -4004,10 +4035,12 @@  gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 	    case AS_EXPLICIT:
 	      if (sym->attr.dummy || sym->attr.result)
 		gfc_trans_dummy_array_bias (sym, sym->backend_decl, block);
-	      /* In a class array the _data component always has the pointer
-		 attribute set.  Therefore only check for allocatable in the
-		 array attributes and for pointer in the symbol.  */
-	      else if (sym->attr.pointer || array_attr->allocatable)
+	      /* Allocatable and pointer arrays need to processed
+		 explicitly.  */
+	      else if ((sym->ts.type != BT_CLASS && sym->attr.pointer)
+		       || (sym->ts.type == BT_CLASS
+			   && CLASS_DATA (sym)->attr.class_pointer)
+		       || array_attr->allocatable)
 		{
 		  if (TREE_STATIC (sym->backend_decl))
 		    {
@@ -4124,6 +4157,7 @@  gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 		}
 	      else
 		{
+		  se.descriptor_only = 1;
 		  gfc_conv_expr (&se, e);
 		  descriptor = se.expr;
 		  se.expr = gfc_conv_descriptor_data_addr (se.expr);
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 9bf976a..664c2c6 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -149,6 +149,11 @@  tree
 gfc_class_vptr_get (tree decl)
 {
   tree vptr;
+  /* For class arrays decl may be a temporary descriptor handle, the vptr is
+     then available through the saved descriptor.  */
+  if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl)
+      && GFC_DECL_SAVED_DESCRIPTOR (decl))
+    decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
   if (POINTER_TYPE_P (TREE_TYPE (decl)))
     decl = build_fold_indirect_ref_loc (input_location, decl);
   vptr = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)),
@@ -163,6 +168,11 @@  tree
 gfc_class_len_get (tree decl)
 {
   tree len;
+  /* For class arrays decl may be a temporary descriptor handle, the len is
+     then available through the saved descriptor.  */
+  if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl)
+      && GFC_DECL_SAVED_DESCRIPTOR (decl))
+    decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
   if (POINTER_TYPE_P (TREE_TYPE (decl)))
     decl = build_fold_indirect_ref_loc (input_location, decl);
   len = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)),
@@ -883,7 +893,11 @@  gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts,
   tmp = NULL_TREE;
   if (class_ref == NULL
 	&& e->symtree && e->symtree->n.sym->ts.type == BT_CLASS)
-    tmp = e->symtree->n.sym->backend_decl;
+    {
+      tmp = e->symtree->n.sym->backend_decl;
+      if (DECL_LANG_SPECIFIC (tmp) && GFC_DECL_SAVED_DESCRIPTOR (tmp))
+	tmp = GFC_DECL_SAVED_DESCRIPTOR (tmp);
+    }
   else
     {
       /* Remove everything after the last class reference, convert the
@@ -918,6 +932,13 @@  gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts,
       tree tmp2;
 
       cond = gfc_conv_expr_present (e->symtree->n.sym);
+      /* parmse->pre may contain some preparatory instructions for the
+ 	 temporary array descriptor.  Those may only be executed when the
+	 optional argument is set, therefore add parmse->pre's instructions
+	 to block, which is later guarded by an if (optional_arg_given).  */
+      gfc_add_block_to_block (&parmse->pre, &block);
+      block.head = parmse->pre.head;
+      parmse->pre.head = NULL_TREE;
       tmp = gfc_finish_block (&block);
 
       if (optional_alloc_ptr)
@@ -1191,6 +1212,8 @@  gfc_trans_class_init_assign (gfc_code *code)
      been referenced.  */
   gfc_get_derived_type (rhs->ts.u.derived);
   gfc_add_def_init_component (rhs);
+  /* The _def_init is always scalar.  */
+  rhs->rank = 0;
 
   if (code->expr1->ts.type == BT_CLASS
 	&& CLASS_DATA (code->expr1)->attr.dimension)
@@ -2246,8 +2269,11 @@  gfc_conv_variable (gfc_se * se, gfc_expr * expr)
   bool return_value;
   bool alternate_entry;
   bool entry_master;
+  bool is_classarray;
+  bool first_time = true;
 
   sym = expr->symtree->n.sym;
+  is_classarray = IS_CLASS_ARRAY (sym);
   ss = se->ss;
   if (ss != NULL)
     {
@@ -2351,9 +2377,24 @@  gfc_conv_variable (gfc_se * se, gfc_expr * expr)
 	}
       else if (!sym->attr.value)
 	{
+	  /* Dereference temporaries for class array dummy arguments.  */
+	  if (sym->attr.dummy && is_classarray
+	      && GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr)))
+	    {
+	      if (!se->descriptor_only)
+		se->expr = GFC_DECL_SAVED_DESCRIPTOR (se->expr);
+
+	      se->expr = build_fold_indirect_ref_loc (input_location,
+						      se->expr);
+	    }
+
 	  /* Dereference non-character scalar dummy arguments.  */
 	  if (sym->attr.dummy && !sym->attr.dimension
-	      && !(sym->attr.codimension && sym->attr.allocatable))
+	      && !(sym->attr.codimension && sym->attr.allocatable)
+	      && (sym->ts.type != BT_CLASS
+		  || (!CLASS_DATA (sym)->attr.dimension
+		      && !(CLASS_DATA (sym)->attr.codimension
+			   && CLASS_DATA (sym)->attr.allocatable))))
 	    se->expr = build_fold_indirect_ref_loc (input_location,
 						se->expr);
 
@@ -2365,11 +2406,12 @@  gfc_conv_variable (gfc_se * se, gfc_expr * expr)
 	    se->expr = build_fold_indirect_ref_loc (input_location,
 						se->expr);
 
-	  /* Dereference non-character pointer variables.
+	  /* Dereference non-character, non-class pointer variables.
 	     These must be dummies, results, or scalars.  */
-	  if ((sym->attr.pointer || sym->attr.allocatable
-	       || gfc_is_associate_pointer (sym)
-	       || (sym->as && sym->as->type == AS_ASSUMED_RANK))
+	  if (!is_classarray
+	      && (sym->attr.pointer || sym->attr.allocatable
+		  || gfc_is_associate_pointer (sym)
+		  || (sym->as && sym->as->type == AS_ASSUMED_RANK))
 	      && (sym->attr.dummy
 		  || sym->attr.function
 		  || sym->attr.result
@@ -2377,6 +2419,32 @@  gfc_conv_variable (gfc_se * se, gfc_expr * expr)
 		      && (!sym->attr.codimension || !sym->attr.allocatable))))
 	    se->expr = build_fold_indirect_ref_loc (input_location,
 						se->expr);
+	  /* Now treat the class array pointer variables accordingly.  */
+	  else if (sym->ts.type == BT_CLASS
+		   && sym->attr.dummy
+		   && (CLASS_DATA (sym)->attr.dimension
+		       || CLASS_DATA (sym)->attr.codimension)
+		   && ((CLASS_DATA (sym)->as
+			&& CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK)
+		       || CLASS_DATA (sym)->attr.allocatable
+		       || CLASS_DATA (sym)->attr.class_pointer))
+	    se->expr = build_fold_indirect_ref_loc (input_location,
+						se->expr);
+	  /* And the case where a non-dummy, non-result, non-function,
+	     non-allotable and non-pointer classarray is present.  This case was
+	     previously covered by the first if, but with introducing the
+	     condition !is_classarray there, that case has to be covered
+	     explicitly.  */
+	  else if (sym->ts.type == BT_CLASS
+		   && !sym->attr.dummy
+		   && !sym->attr.function
+		   && !sym->attr.result
+		   && (CLASS_DATA (sym)->attr.dimension
+		       || CLASS_DATA (sym)->attr.codimension)
+		   && !CLASS_DATA (sym)->attr.allocatable
+		   && !CLASS_DATA (sym)->attr.class_pointer)
+	    se->expr = build_fold_indirect_ref_loc (input_location,
+						se->expr);
 	}
 
       ref = expr->ref;
@@ -2414,6 +2482,18 @@  gfc_conv_variable (gfc_se * se, gfc_expr * expr)
 	  break;
 
 	case REF_COMPONENT:
+	  if (first_time && is_classarray && sym->attr.dummy
+	      && se->descriptor_only
+	      && !CLASS_DATA (sym)->attr.allocatable
+	      && !CLASS_DATA (sym)->attr.class_pointer
+	      && CLASS_DATA (sym)->as
+	      && CLASS_DATA (sym)->as->type != AS_ASSUMED_RANK
+	      && strcmp ("_data", ref->u.c.component->name) == 0)
+	    /* Skip the first ref of a _data component, because for class
+	       arrays that one is already done by introducing a temporary
+	       array descriptor.  */
+	    break;
+
 	  if (ref->u.c.sym->attr.extension)
 	    conv_parent_component_references (se, ref);
 
@@ -2433,6 +2513,7 @@  gfc_conv_variable (gfc_se * se, gfc_expr * expr)
 	  gcc_unreachable ();
 	  break;
 	}
+      first_time = false;
       ref = ref->next;
     }
   /* Pointer assignment, allocation or pass by reference.  Arrays are handled
@@ -4559,7 +4640,19 @@  gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 	  gfc_init_se (&parmse, se);
 	  parm_kind = ELEMENTAL;
 
-	  if (fsym && fsym->attr.value)
+	  /* For all value functions or polymorphic scalar non-pointer
+	     non-allocatable variables use the expression in e directly.  This
+	     ensures, that initializers of polymorphic entities are correctly
+	     copied.  */
+	  if (fsym && (fsym->attr.value
+		       || (e->expr_type == EXPR_VARIABLE
+			   && fsym->ts.type == BT_DERIVED
+			   && e->ts.type == BT_DERIVED
+			   && !e->ts.u.derived->attr.dimension
+			   && !e->rank
+			   && (!e->symtree
+			       || (!e->symtree->n.sym->attr.allocatable
+				   && !e->symtree->n.sym->attr.pointer)))))
 	    gfc_conv_expr (&parmse, e);
 	  else
 	    gfc_conv_expr_reference (&parmse, e);
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index c4ccb7b..cb693c0 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -5921,8 +5921,17 @@  gfc_conv_intrinsic_sizeof (gfc_se *se, gfc_expr *expr)
     }
   else if (arg->ts.type == BT_CLASS)
     {
-      if (arg->rank)
+      /* For deferred length arrays, conv_expr_descriptor returns an
+	 indirect_ref to the component.  */
+      if (arg->rank < 0
+	  || (arg->rank > 0 && !VAR_P (argse.expr)
+	      && GFC_DECL_CLASS (TREE_OPERAND (argse.expr, 0))))
 	byte_size = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0));
+      else if (arg->rank > 0)
+	/* The scalarizer added an additional temp.  To get the class' vptr
+	   one has to look at the original backend_decl.  */
+	byte_size = gfc_class_vtab_size_get (
+	      GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl));
       else
 	byte_size = gfc_class_vtab_size_get (argse.expr);
     }
@@ -6053,7 +6062,11 @@  gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr)
       gfc_conv_expr_descriptor (&argse, arg);
       if (arg->ts.type == BT_CLASS)
 	{
-	  tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0));
+	  if (arg->rank > 0)
+	    tmp = gfc_class_vtab_size_get (
+		 GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl));
+	  else
+	    tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0));
 	  tmp = fold_convert (result_type, tmp);
 	  goto done;
 	}
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index a6fb52c..6ffae6e79e 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -1260,12 +1260,29 @@  trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
 
       gfc_init_se (&se, NULL);
       se.descriptor_only = 1;
-      gfc_conv_expr (&se, e);
+      /* In a select type the (temporary) associate variable shall point to
+	 a standart fortran array (lower bound == 1), but conv_expr ()
+	 just maps to the input array in the class object, whose lbound may
+	 be arbitrary.  conv_expr_descriptor solves this by inserting a
+	 temporary array descriptor.  */
+      gfc_conv_expr_descriptor (&se, e);
 
-      gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)));
+      gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr))
+		  || GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr)));
       gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (sym->backend_decl)));
 
-      gfc_add_modify (&se.pre, sym->backend_decl, se.expr);
+      if (GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr)))
+	{
+	  if (INDIRECT_REF_P (se.expr))
+	    tmp = TREE_OPERAND (se.expr, 0);
+	  else
+	    tmp = se.expr;
+
+	  gfc_add_modify (&se.pre, sym->backend_decl,
+			  gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR (tmp)));
+	}
+      else
+	gfc_add_modify (&se.pre, sym->backend_decl, se.expr);
 
       if (unlimited)
 	{
@@ -1276,7 +1293,7 @@  trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
 			  gfc_get_dtype (TREE_TYPE (sym->backend_decl)));
 	}
 
-      gfc_add_init_cleanup (block, gfc_finish_block( &se.pre),
+      gfc_add_init_cleanup (block, gfc_finish_block (&se.pre),
 			    gfc_finish_block (&se.post));
     }
 
@@ -1319,9 +1336,18 @@  trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
 	    }
 	  if (need_len_assign)
 	    {
-	      /* Get the _len comp from the target expr by stripping _data
-		 from it and adding component-ref to _len.  */
-	      tmp = gfc_class_len_get (TREE_OPERAND (target_expr, 0));
+	      if (e->symtree
+		  && DECL_LANG_SPECIFIC (e->symtree->n.sym->backend_decl)
+		 && GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl))
+		/* Use the original class descriptor stored in the saved
+		   descriptor to get the target_expr.  */
+		target_expr =
+		    GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl);
+	      else
+		/* Strip the _data component from the target_expr.  */
+		target_expr = TREE_OPERAND (target_expr, 0);
+	      /* Add a reference to the _len comp to the target expr.  */
+	      tmp = gfc_class_len_get (target_expr);
 	      /* Get the component-ref for the temp structure's _len comp.  */
 	      charlen = gfc_class_len_get (se.expr);
 	      /* Add the assign to the beginning of the the block...  */
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 1838a2e..b9f662d 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -1290,14 +1290,17 @@  gfc_is_nodesc_array (gfc_symbol * sym)
 {
   symbol_attribute *array_attr;
   gfc_array_spec *as;
+  bool is_classarray = IS_CLASS_ARRAY (sym);
 
-  array_attr = &sym->attr;
-  as = sym->as;
+  array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr;
+  as = is_classarray ? CLASS_DATA (sym)->as : sym->as;
 
   gcc_assert (array_attr->dimension || array_attr->codimension);
 
   /* We only want local arrays.  */
-  if (sym->attr.pointer || array_attr->allocatable)
+  if ((sym->ts.type != BT_CLASS && sym->attr.pointer)
+      || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer)
+      || array_attr->allocatable)
     return 0;
 
   /* We want a descriptor for associate-name arrays that do not have an
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index b7ec0e5..394745e 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -362,16 +362,23 @@  gfc_build_array_ref (tree base, tree offset, tree decl)
     {
       if (GFC_DECL_CLASS (decl))
 	{
-	  /* Allow for dummy arguments and other good things.  */
-	  if (POINTER_TYPE_P (TREE_TYPE (decl)))
-	    decl = build_fold_indirect_ref_loc (input_location, decl);
-
-	  /* Check if '_data' is an array descriptor. If it is not,
-	     the array must be one of the components of the class object,
-	     so return a normal array reference.  */
-	  if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl))))
-	    return build4_loc (input_location, ARRAY_REF, type, base,
-			       offset, NULL_TREE, NULL_TREE);
+	  /* When a temporary is in place for the class array, then the original
+	     class' declaration is stored in the saved descriptor.  */
+	  if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl))
+	    decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
+	  else
+	    {
+	      /* Allow for dummy arguments and other good things.  */
+	      if (POINTER_TYPE_P (TREE_TYPE (decl)))
+		decl = build_fold_indirect_ref_loc (input_location, decl);
+
+	      /* Check if '_data' is an array descriptor.  If it is not,
+		 the array must be one of the components of the class object,
+		 so return a normal array reference.  */
+	      if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl))))
+		return build4_loc (input_location, ARRAY_REF, type, base,
+				   offset, NULL_TREE, NULL_TREE);
+	    }
 
 	  span = gfc_class_vtab_size_get (decl);
 	}
diff --git a/gcc/testsuite/gfortran.dg/class_array_20.f03 b/gcc/testsuite/gfortran.dg/class_array_20.f03
new file mode 100644
index 0000000..c49f7d2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/class_array_20.f03
@@ -0,0 +1,100 @@ 
+! {dg-do run}
+!
+! Test contributed by Thomas L. Clune via pr60322
+!                  and Antony Lewis via pr64692
+
+program class_array_20
+  implicit none
+
+  type Foo
+  end type
+
+  type(foo), dimension(2:3) :: arg
+  integer :: oneDarr(2)
+  integer :: twoDarr(2,3)
+  integer :: x, y
+  double precision :: P(2, 2)
+
+  ! Checking for PR/60322
+  call copyFromClassArray([Foo(), Foo()])
+  call copyFromClassArray(arg)
+  call copyFromClassArray(arg(:))
+
+  x= 3
+  y= 4
+  oneDarr = [x, y]
+  call W([x, y])
+  call W(oneDarr)
+  call W([3, 4])
+
+  twoDarr = reshape([3, 4, 5, 5, 6, 7], [2, 3])
+  call WtwoD(twoDarr)
+  call WtwoD(reshape([3, 4, 5, 5, 6, 7], [2, 3]))
+
+  ! Checking for PR/64692
+  P(1:2, 1) = [1.d0, 2.d0]
+  P(1:2, 2) = [3.d0, 4.d0]
+  call AddArray(P(1:2, 2))
+
+contains
+
+  subroutine copyFromClassArray(classarray)
+    class (Foo), intent(in) :: classarray(:)
+
+    if (lbound(classarray, 1) .ne. 1) call abort()
+    if (ubound(classarray, 1) .ne. 2) call abort()
+    if (size(classarray) .ne. 2) call abort()
+  end subroutine
+
+  subroutine AddArray(P)
+    class(*), target, intent(in) :: P(:)
+    class(*), pointer :: Pt(:)
+
+    allocate(Pt(1:size(P)), source= P)
+
+    select type (P)
+      type is (double precision)
+        if (abs(P(1)-3.d0) .gt. 1.d-8) call abort()
+        if (abs(P(2)-4.d0) .gt. 1.d-8) call abort()
+      class default
+        call abort()
+    end select
+
+    select type (Pt)
+      type is (double precision)
+        if (abs(Pt(1)-3.d0) .gt. 1.d-8) call abort()
+        if (abs(Pt(2)-4.d0) .gt. 1.d-8) call abort()
+      class default
+        call abort()
+    end select
+  end subroutine
+
+  subroutine W(ar)
+    class(*), intent(in) :: ar(:)
+
+    if (lbound(ar, 1) /= 1) call abort()
+    select type (ar)
+      type is (integer)
+        ! The indeces 1:2 are essential here, or else one would not
+        ! note, that the array internally starts at 0, although the
+        ! check for the lbound above went fine.
+        if (any (ar(1:2) .ne. [3, 4])) call abort()
+      class default
+        call abort()
+    end select
+  end subroutine
+
+  subroutine WtwoD(ar)
+    class(*), intent(in) :: ar(:,:)
+
+    if (any (lbound(ar) /= [1, 1])) call abort()
+    select type (ar)
+      type is (integer)
+        if (any (reshape(ar(1:2,1:3), [6]) .ne. [3, 4, 5, 5, 6, 7])) &
+        call abort()
+      class default
+        call abort()
+    end select
+  end subroutine
+end program class_array_20
+
diff --git a/gcc/testsuite/gfortran.dg/finalize_10.f90 b/gcc/testsuite/gfortran.dg/finalize_10.f90
index e042f11..32386ce 100644
--- a/gcc/testsuite/gfortran.dg/finalize_10.f90
+++ b/gcc/testsuite/gfortran.dg/finalize_10.f90
@@ -27,8 +27,8 @@  end subroutine foo
 ! Finalize CLASS + set default init
 ! { dg-final { scan-tree-dump-times "y->_vptr->_final \\(&desc.\[0-9\]+, y->_vptr->_size, 0\\);" 1 "original" } }
 ! { dg-final { scan-tree-dump       "__builtin_memcpy \\(\\(void .\\) y->_data, \\(void .\\) y->_vptr->_def_init, \\((unsigned long|unsigned int|character\\(kind=4\\))\\) y->_vptr->_size\\);" "original" } }
-! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&x->_data, x->_vptr->_size, 0\\);" 1 "original" } }
-! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(x->_vptr->_def_init, &x->_data\\);" 1 "original" } }
+! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&parm.\[0-9\]+, x->_vptr->_size, 0\\);" 1 "original" } }
+! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(" 1 "original" } }
 
 ! FINALIZE TYPE:
 ! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void \\*\\) &\\(\\*aa.\[0-9\]+\\)\\\[0\\\];" 1 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/finalize_15.f90 b/gcc/testsuite/gfortran.dg/finalize_15.f90
index 3c18b2a..d5ba28f 100644
--- a/gcc/testsuite/gfortran.dg/finalize_15.f90
+++ b/gcc/testsuite/gfortran.dg/finalize_15.f90
@@ -9,37 +9,37 @@  module m
   implicit none
 
   type t1
-    integer :: i
+    integer :: i = 1
   contains
     final :: fini_elem
   end type t1
 
   type, extends(t1) :: t1e
-    integer :: j
+    integer :: j = 11
   contains
     final :: fini_elem2
   end type t1e
 
   type t2
-    integer :: i
+    integer :: i = 2
   contains
     final :: fini_shape
   end type t2
 
   type, extends(t2) :: t2e
-    integer :: j
+    integer :: j = 22
   contains
     final :: fini_shape2
   end type t2e
 
   type t3
-    integer :: i
+    integer :: i = 3
   contains
     final :: fini_explicit
   end type t3
 
   type, extends(t3) :: t3e
-    integer :: j
+    integer :: j = 33
   contains
     final :: fini_explicit2
   end type t3e
@@ -204,31 +204,31 @@  program test
 
   select type(x)
     type is (t1e)
-      call check_val(x%i, 1)
-      call check_val(x%j, 100)
+      call check_val(x%i, 1, 1)
+      call check_val(x%j, 100, 11)
   end select
 
   select type(y)
     type is (t2e)
-      call check_val(y%i, 1)
-      call check_val(y%j, 100)
+      call check_val(y%i, 1, 2)
+      call check_val(y%j, 100, 22)
   end select
 
   select type(z)
     type is (t3e)
-      call check_val(z%i, 1)
-      call check_val(z%j, 100)
+      call check_val(z%i, 1, 3)
+      call check_val(z%j, 100, 33)
   end select
 
 contains
-  subroutine check_val(x, factor)
+  subroutine check_val(x, factor, val)
     integer :: x(:,:)
-    integer, value :: factor
+    integer, value :: factor, val
     integer :: i, j
     do i = 1, 10
       do j = 1, 10
         if (mod (j-1, 2) == 0 .and. mod (i-1, 3) == 0) then
-          if (x(j,i) /= (j + 100*i)*factor*(-13)) call abort ()
+          if (x(j,i) /= val) call abort ()
         else
           if (x(j,i) /= (j + 100*i)*factor) call abort ()
         end if
diff --git a/gcc/testsuite/gfortran.dg/finalize_29.f08 b/gcc/testsuite/gfortran.dg/finalize_29.f08
new file mode 100644
index 0000000..1f5f7424
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/finalize_29.f08
@@ -0,0 +1,289 @@ 
+! {dg-do run}
+!
+! Testcase contributed by Andre Vehreschild  <vehre@gcc.gnu.org>
+
+module module_finalize_29
+  implicit none
+
+  ! The type name is encoding the state of its finalizer being
+  ! elemental (second letter 'e'), or non-element (second letter 'n')
+  ! or array shaped (second letter 'a'), or shape-specific routine
+  ! (generic; second letter 'g'),
+  ! and whether the init-routine is elemental or not (third letter
+  ! either 'e' or 'n').
+  type ten
+    integer :: i = 40
+  contains
+    final :: ten_fin
+  end type ten
+
+  type tee
+    integer :: i = 41
+  contains
+    final :: tee_fin
+  end type tee
+
+  type tne
+    integer :: i = 42
+  contains
+    final :: tne_fin
+  end type tne
+
+  type tnn
+    integer :: i = 43
+  contains
+    final :: tnn_fin
+  end type tnn
+
+  type tae
+    integer :: i = 44
+  contains
+    final :: tae_fin
+  end type tae
+
+  type tan
+    integer :: i = 45
+  contains
+    final :: tan_fin
+  end type tan
+
+  type tge
+    integer :: i = 46
+  contains
+    final :: tge_scalar_fin, tge_array_fin
+  end type tge
+
+  type tgn
+    integer :: i = 47
+  contains
+    final :: tgn_scalar_fin, tgn_array_fin
+  end type tgn
+
+  integer :: ten_fin_counts, tee_fin_counts, tne_fin_counts, tnn_fin_counts
+  integer :: tae_fin_counts, tan_fin_counts
+  integer :: tge_scalar_fin_counts, tge_array_fin_counts
+  integer :: tgn_scalar_fin_counts, tgn_array_fin_counts
+contains
+  impure elemental subroutine ten_fin(x)
+    type(ten), intent(inout) :: x
+    x%i = -10 * x%i
+    ten_fin_counts = ten_fin_counts + 1
+  end subroutine ten_fin
+
+  impure elemental subroutine tee_fin(x)
+    type(tee), intent(inout) :: x
+    x%i = -11 * x%i
+    tee_fin_counts = tee_fin_counts + 1
+  end subroutine tee_fin
+
+  subroutine tne_fin(x)
+    type(tne), intent(inout) :: x
+    x%i = -12 * x%i
+    tne_fin_counts = tne_fin_counts + 1
+  end subroutine tne_fin
+
+  subroutine tnn_fin(x)
+    type(tnn), intent(inout) :: x
+    x%i = -13 * x%i
+    tnn_fin_counts = tnn_fin_counts + 1
+  end subroutine tnn_fin
+
+  subroutine tae_fin(x)
+    type(tae), intent(inout) :: x(:,:)
+    x%i = -14 * x%i
+    tae_fin_counts = tae_fin_counts + 1
+  end subroutine tae_fin
+
+  subroutine tan_fin(x)
+    type(tan), intent(inout) :: x(:,:)
+    x%i = -15 * x%i
+    tan_fin_counts = tan_fin_counts + 1
+  end subroutine tan_fin
+
+  subroutine tge_scalar_fin(x)
+    type(tge), intent(inout) :: x
+    x%i = -16 * x%i
+    tge_scalar_fin_counts = tge_scalar_fin_counts + 1
+  end subroutine tge_scalar_fin
+
+  subroutine tge_array_fin(x)
+    type(tge), intent(inout) :: x(:,:)
+    x%i = -17 * x%i
+    tge_array_fin_counts = tge_array_fin_counts + 1
+  end subroutine tge_array_fin
+
+  subroutine tgn_scalar_fin(x)
+    type(tgn), intent(inout) :: x
+    x%i = -18 * x%i
+    tgn_scalar_fin_counts = tgn_scalar_fin_counts + 1
+  end subroutine tgn_scalar_fin
+
+  subroutine tgn_array_fin(x)
+    type(tgn), intent(inout) :: x(:,:)
+    x%i = -19 * x%i
+    tgn_array_fin_counts = tgn_array_fin_counts + 1
+  end subroutine tgn_array_fin
+
+  ! The finalizer/initializer call producer
+  subroutine ten_init(x)
+    class(ten), intent(out) :: x(:,:)
+  end subroutine ten_init
+
+  impure elemental subroutine tee_init(x)
+    class(tee), intent(out) :: x
+  end subroutine tee_init
+
+  impure elemental subroutine tne_init(x)
+    class(tne), intent(out) :: x
+  end subroutine tne_init
+
+  subroutine tnn_init(x)
+    class(tnn), intent(out) :: x(:,:)
+  end subroutine tnn_init
+
+  impure elemental subroutine tae_init(x)
+    class(tae), intent(out) :: x
+  end subroutine tae_init
+
+  subroutine tan_init(x)
+    class(tan), intent(out) :: x(:,:)
+  end subroutine tan_init
+
+  impure elemental subroutine tge_init(x)
+    class(tge), intent(out) :: x
+  end subroutine tge_init
+
+  subroutine tgn_init(x)
+    class(tgn), intent(out) :: x(:,:)
+  end subroutine tgn_init
+end module module_finalize_29
+
+program finalize_29
+  use module_finalize_29
+  implicit none
+
+  type(ten), allocatable :: x_ten(:,:)
+  type(tee), allocatable :: x_tee(:,:)
+  type(tne), allocatable :: x_tne(:,:)
+  type(tnn), allocatable :: x_tnn(:,:)
+  type(tae), allocatable :: x_tae(:,:)
+  type(tan), allocatable :: x_tan(:,:)
+  type(tge), allocatable :: x_tge(:,:)
+  type(tgn), allocatable :: x_tgn(:,:)
+
+  ! Set the global counts to zero.
+  ten_fin_counts = 0
+  tee_fin_counts = 0
+  tne_fin_counts = 0
+  tnn_fin_counts = 0
+  tae_fin_counts = 0
+  tan_fin_counts = 0
+  tge_scalar_fin_counts = 0
+  tge_array_fin_counts = 0
+  tgn_scalar_fin_counts = 0
+  tgn_array_fin_counts = 0
+
+  allocate(ten :: x_ten(5,5))
+  allocate(tee :: x_tee(5,5))
+  allocate(tne :: x_tne(5,5))
+  allocate(tnn :: x_tnn(5,5))
+  allocate(tae :: x_tae(5,5))
+  allocate(tan :: x_tan(5,5))
+  allocate(tge :: x_tge(5,5))
+  allocate(tgn :: x_tgn(5,5))
+
+  x_ten%i = 1
+  x_tee%i = 2
+  x_tne%i = 3
+  x_tnn%i = 4
+  x_tae%i = 5
+  x_tan%i = 6
+  x_tge%i = 7
+  x_tgn%i = 8
+
+  call ten_init(x_ten(::2, ::3))
+
+  if (ten_fin_counts /= 6) call abort()
+  if (tee_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + &
+        tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + &
+        tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort()
+  ten_fin_counts = 0
+
+  call tee_init(x_tee(::2, ::3))
+
+  if (tee_fin_counts /= 6) call abort()
+  if (ten_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + &
+        tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + &
+        tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort()
+  tee_fin_counts = 0
+
+  call tne_init(x_tne(::2, ::3))
+
+  if (tne_fin_counts /= 6) call abort()
+  if (ten_fin_counts + tee_fin_counts + tnn_fin_counts + tae_fin_counts + &
+        tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + &
+        tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort()
+  tne_fin_counts = 0
+
+  call tnn_init(x_tnn(::2, ::3))
+
+  if (tnn_fin_counts /= 0) call abort()
+  if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tae_fin_counts + &
+        tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + &
+        tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort()
+
+  call tae_init(x_tae(::2, ::3))
+
+  if (tae_fin_counts /= 0) call abort()
+  if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + &
+        tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + &
+        tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort()
+
+  call tan_init(x_tan(::2, ::3))
+
+  if (tan_fin_counts /= 1) call abort()
+  if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + &
+        tae_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + &
+        tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort()
+  tan_fin_counts = 0
+
+  call tge_init(x_tge(::2, ::3))
+
+  if (tge_scalar_fin_counts /= 6) call abort()
+  if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + &
+        tae_fin_counts + tan_fin_counts + tgn_array_fin_counts + &
+        tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort()
+  tge_scalar_fin_counts = 0
+
+  call tgn_init(x_tgn(::2, ::3))
+
+  if (tgn_array_fin_counts /= 1) call abort()
+  if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + &
+        tae_fin_counts + tan_fin_counts + tge_scalar_fin_counts + &
+        tge_array_fin_counts + tgn_scalar_fin_counts /= 0) call abort()
+  tgn_array_fin_counts = 0
+
+  if (any (reshape (x_ten%i, [25]) /= [[40, 1, 40, 1, 40], [1, 1, 1, 1, 1],&
+        [1, 1, 1, 1, 1], [40, 1, 40, 1, 40], [1, 1, 1, 1, 1]])) call abort()
+
+  if (any (reshape (x_tee%i, [25]) /= [[41, 2, 41, 2, 41], [2, 2, 2, 2, 2],&
+        [2, 2, 2, 2, 2], [41, 2, 41, 2, 41], [2, 2, 2, 2, 2]])) call abort()
+
+  if (any (reshape (x_tne%i, [25]) /= [[42, 3, 42, 3, 42], [3, 3, 3, 3, 3],&
+        [3, 3, 3, 3, 3], [42, 3, 42, 3, 42], [3, 3, 3, 3, 3]])) call abort()
+
+  if (any (reshape (x_tnn%i, [25]) /= [[43, 4, 43, 4, 43], [4, 4, 4, 4, 4],&
+        [4, 4, 4, 4, 4], [43, 4, 43, 4, 43], [4, 4, 4, 4, 4]])) call abort()
+
+  if (any (reshape (x_tae%i, [25]) /= [[44, 5, 44, 5, 44], [5, 5, 5, 5, 5],&
+        [5, 5, 5, 5, 5], [44, 5, 44, 5, 44], [5, 5, 5, 5, 5]])) call abort()
+
+  if (any (reshape (x_tan%i, [25]) /= [[45, 6, 45, 6, 45], [6, 6, 6, 6, 6],&
+        [6, 6, 6, 6, 6], [45, 6, 45, 6, 45], [6, 6, 6, 6, 6]])) call abort()
+
+  if (any (reshape (x_tge%i, [25]) /= [[46, 7, 46, 7, 46], [7, 7, 7, 7, 7],&
+        [7, 7, 7, 7, 7], [46, 7, 46, 7, 46], [7, 7, 7, 7, 7]])) call abort()
+
+  if (any (reshape (x_tgn%i, [25]) /= [[47, 8, 47, 8, 47], [8, 8, 8, 8, 8],&
+        [8, 8, 8, 8, 8], [47, 8, 47, 8, 47], [8, 8, 8, 8, 8]])) call abort()
+end program finalize_29