Dear All,

This is a straightforward patch that is completely described in the
ChangeLog entry. I am surprised that this could be a 4.8 regression
since, as far as I am aware, SELECT_TYPE was not capable of handling
array selectors before... Nonetheless, it flagged it up for me :-)

Bootstrapped and regtested on FC17/x86_64 - OK for trunk and, after a
decent delay, 4.8?

Cheers

Paul

PS I know of at least one other place where this manoeuvre had to be
done.  If I find a third, I will turn it into a function in class.c.
It might be worth doing anyway?

2014-01-20  Paul Thomas  <pa...@gcc.gnu.org>

    PR fortran/59414
    * trans-stmt.c (gfc_trans_allocate): Before the pointer
    assignment to transfer the source _vptr to a class allocate
    expression, the final class reference should be exposed. The
    tail that includes the _data and array references is stored.
    This reduced expression is transferred to 'lhs' and the _vptr
    added. Then the tail is restored to the allocate expression.

2014-01-20  Paul Thomas  <pa...@gcc.gnu.org>

    PR fortran/59414
    * gfortran.dg/allocate_class_3.f90 : New test
Index: gcc/fortran/trans-stmt.c
===================================================================
*** gcc/fortran/trans-stmt.c    (revision 206747)
--- gcc/fortran/trans-stmt.c    (working copy)
*************** gfc_trans_allocate (gfc_code * code)
*** 5102,5111 ****
--- 5102,5150 ----
        {
          gfc_expr *lhs, *rhs;
          gfc_se lse;
+         gfc_ref *ref, *class_ref, *tail;
+ 
+         /* Find the last class reference.  */
+         class_ref = NULL;
+         for (ref = e->ref; ref; ref = ref->next)
+           {
+             if (ref->type == REF_COMPONENT
+                 && ref->u.c.component->ts.type == BT_CLASS)
+               class_ref = ref;
+ 
+             if (ref->next == NULL)
+               break;
+           }
+ 
+         /* Remove and store all subsequent references after the
+            CLASS reference.  */
+         if (class_ref)
+           {
+             tail = class_ref->next;
+             class_ref->next = NULL;
+           }
+         else
+           {
+             tail = e->ref;
+             e->ref = NULL;
+           }
  
          lhs = gfc_expr_to_initialize (e);
          gfc_add_vptr_component (lhs);
  
+         /* Remove the _vptr component and restore the original tail
+            references.  */
+         if (class_ref)
+           {
+             gfc_free_ref_list (class_ref->next);
+             class_ref->next = tail;
+           }
+         else
+           {
+             gfc_free_ref_list (e->ref);
+             e->ref = tail;
+           }
+ 
          if (class_expr != NULL_TREE)
            {
              /* Polymorphic SOURCE: VPTR must be determined at run time.  */
Index: gcc/testsuite/gfortran.dg/allocate_class_3.f90
===================================================================
*** gcc/testsuite/gfortran.dg/allocate_class_3.f90      (revision 0)
--- gcc/testsuite/gfortran.dg/allocate_class_3.f90      (working copy)
***************
*** 0 ****
--- 1,107 ----
+ ! { dg-do run }
+ ! Tests the fix for PR59414, comment #3, in which the allocate
+ ! expressions were not correctly being stripped to provide the
+ ! vpointer as an lhs to the pointer assignment of the vptr from
+ ! the SOURCE expression.
+ !
+ ! Contributed by Antony Lewis  <ant...@cosmologist.info>
+ !
+ module ObjectLists
+   implicit none
+ 
+   type :: t
+     integer :: i
+   end type
+ 
+   type Object_array_pointer
+     class(t), pointer :: p(:)
+   end type
+ 
+ contains
+ 
+   subroutine AddArray1 (P, Pt)
+     class(t) :: P(:)
+     class(Object_array_pointer) :: Pt
+ 
+     select type (Pt)
+     class is (Object_array_pointer)
+       if (associated (Pt%P)) deallocate (Pt%P)
+       allocate(Pt%P(1:SIZE(P)), source=P)
+     end select
+   end subroutine
+ 
+   subroutine AddArray2 (P, Pt)
+     class(t) :: P(:)
+     class(Object_array_pointer) :: Pt
+ 
+     select type (Pt)
+     type is (Object_array_pointer)
+       if (associated (Pt%P)) deallocate (Pt%P)
+       allocate(Pt%P(1:SIZE(P)), source=P)
+     end select
+   end subroutine
+ 
+   subroutine AddArray3 (P, Pt)
+     class(t) :: P
+     class(Object_array_pointer) :: Pt
+ 
+     select type (Pt)
+     class is (Object_array_pointer)
+       if (associated (Pt%P)) deallocate (Pt%P)
+       allocate(Pt%P(1:4), source=P)
+     end select
+   end subroutine
+ 
+   subroutine AddArray4 (P, Pt)
+     type(t) :: P(:)
+     class(Object_array_pointer) :: Pt
+ 
+     select type (Pt)
+     class is (Object_array_pointer)
+       if (associated (Pt%P)) deallocate (Pt%P)
+       allocate(Pt%P(1:SIZE(P)), source=P)
+     end select
+   end subroutine
+ end module
+ 
+   use ObjectLists
+   type(Object_array_pointer), pointer :: Pt
+   class(t), pointer :: P(:)
+ 
+   allocate (P(2), source = [t(1),t(2)])
+   allocate (Pt, source = Object_array_pointer(NULL()))
+   call AddArray1 (P, Pt)
+   select type (x => Pt%p)
+     type is (t)
+       if (any (x%i .ne. [1,2])) call abort
+   end select
+   deallocate (P)
+   deallocate (pt)
+ 
+   allocate (P(3), source = [t(3),t(4),t(5)])
+   allocate (Pt, source = Object_array_pointer(NULL()))
+   call AddArray2 (P, Pt)
+   select type (x => Pt%p)
+     type is (t)
+       if (any (x%i .ne. [3,4,5])) call abort
+   end select
+   deallocate (P)
+   deallocate (pt)
+ 
+   allocate (Pt, source = Object_array_pointer(NULL()))
+   call AddArray3 (t(6), Pt)
+   select type (x => Pt%p)
+     type is (t)
+       if (any (x%i .ne. [6,6,6,6])) call abort
+   end select
+   deallocate (pt)
+ 
+   allocate (Pt, source = Object_array_pointer(NULL()))
+   call AddArray4 ([t(7), t(8)], Pt)
+   select type (x => Pt%p)
+     type is (t)
+       if (any (x%i .ne. [7,8])) call abort
+   end select
+   deallocate (pt)
+  end
+ 

Reply via email to