This is a relatively obvious patch. The chunk in trans-array.c is not part
of the fix for the PR but does suppress some of the bad dtype's that arise
from allocation of class objects. The part in trans-stmt.c provides vptrs
for all class allocations if the expression3 is available.

Regtests on FC33/x86_64

Paul

Fortran: Fix missing setting of vptrs in allocate statements [PR98573].

2021-01-22  Paul Thomas  <pa...@gcc.gnu.org>

gcc/fortran
PR fortran/98573
* trans-array.c (gfc_array_init_size): If expr3 descriptor is
present, use it for the type.
* trans-stmt.c (gfc_trans_allocate): Use the expr3 vptr for all
class allocations.

gcc/testsuite/
PR fortran/98573
* gfortran.dg/associated_target_7.f90 : New test.
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 4bd4db877bd..306c2de7be7 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -5540,7 +5540,13 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
   gfc_se se;
   int n;
 
-  type = TREE_TYPE (descriptor);
+  if (expr->ts.type == BT_CLASS
+      && expr3_desc != NULL_TREE
+      && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (expr3_desc)))
+    type = TREE_TYPE (expr3_desc);
+  else
+    type = TREE_TYPE (descriptor);
+
 
   stride = gfc_index_one_node;
   offset = gfc_index_zero_node;
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index 547468f7648..2bd7fdf0f1c 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -6908,7 +6908,8 @@ gfc_trans_allocate (gfc_code * code)
 
       /* Set the vptr only when no source= is set.  When source= is set, then
 	 the trans_assignment below will set the vptr.  */
-      if (al_vptr != NULL_TREE && (!code->expr3 || code->expr3->mold))
+      if (al_vptr != NULL_TREE && (!code->expr3 || code->expr3->mold
+				   || code->expr3->ts.type == BT_CLASS))
 	{
 	  if (expr3_vptr != NULL_TREE)
 	    /* The vtab is already known, so just assign it.  */
! { dg-do run }
!
! Tests the fix of PR98573. Fixed missing vptrs for class allocations.
!
! Contributed by Davis Asanza  <davidhne...@gmail.com>
!
module counts
  integer :: integer_count = 0
  integer :: other_count = 0
  integer :: alloc_counts = 0
end module counts

module foo1
  use counts
  type, public:: box
    class(*), allocatable :: val(:)
  end type
contains
  subroutine store1(this, val)
    class(box), intent(out) :: this
    class(*), intent(in) :: val(:)
    this%val = val
  end subroutine store1
  subroutine store2(this, val)
    class(box), intent(out) :: this
    class(*), intent(in) :: val(:)
    allocate(this%val, source=val)
  end subroutine store2
  subroutine vector_type(val)
    class(*), intent(in) :: val(:)
    select type (val)
    type is (integer)
      integer_count = integer_count + 1
    class default
      other_count = other_count + 1
    end select
  end subroutine vector_type
end module foo1

module foo2
  use counts
contains
  subroutine store1(arr, val)
    class(*), allocatable, intent(out) :: arr(:)
    class(*), intent(in) :: val(:)
    arr = val
  end subroutine store1
  subroutine store2(arr, val)
    class(*), allocatable, intent(out) :: arr(:)
    class(*), intent(in) :: val(:)
    allocate(arr, source=val)
  end subroutine store2
end module foo2

module foo3
  use counts
  type, public:: box
    class(*), allocatable :: val(:)
  end type
contains
  subroutine store1(this, val)
    class(box), intent(out) :: this
    class(*), intent(in) :: val(:)
    this%val = val
  end subroutine store1
  subroutine store2(this, val)
    class(box), intent(out) :: this
    class(*), intent(in) :: val(:)
    allocate(this%val, source=val)
  end subroutine store2
  subroutine vector_type(val)
    class(*), intent(in) :: val(:)
    select type (val)
    type is (integer)
      integer_count = integer_count + 1
    class default
      other_count = other_count + 1
    end select
  end subroutine vector_type
end module foo3

program prog
  use counts
  implicit none
  call bar1  ! Test the original problem
  call bar2  ! Test comment 1
  call bar3  ! Test comment 3
  if (integer_count .ne. 6) stop 1
  if (other_count .ne. 0) stop 2
  if (alloc_counts .ne. 2) stop 3
contains
  subroutine bar1
    use foo1
    type(box) :: b
    call store1(b, [1, 2, 3])
    call vector_type(b%val)  ! OTHER
    call store2(b, [1, 2, 3])
    call vector_type(b%val)  ! INTEGER
  end subroutine bar1

  subroutine bar2
    use foo2
    class(*), allocatable :: arr(:)
    call store1(arr, [1, 2, 3])  ! SEGFAULT
    select type (a => arr)
      type is (integer)
        if (all (a .eq. [1, 2, 3])) alloc_counts = alloc_counts + 1
    end select
    deallocate (arr)
    call store2(arr, [1, 2, 3])  ! NO PROBLEM
    select type (a => arr)
      type is (integer)
        if (all (a .eq. [1, 2, 3])) alloc_counts = alloc_counts + 1
    end select
  end subroutine bar2

  subroutine bar3
    use foo3
    type(box) :: b
    integer, allocatable :: arr1(:)
    integer, dimension(0) :: arr2

    allocate(arr1(0))
    call store1(b, arr1)
    call vector_type(b%val)  ! OTHER
    call store2(b, arr1)
    call vector_type(b%val)  ! OTHER

    call store1(b, arr2)
    call vector_type(b%val)  ! OTHER
    call store2(b, arr2)
    call vector_type(b%val)  ! OTHER
  end subroutine bar3
end program

Reply via email to