Dear all,

here's a - once found - seemingly simple and obvious fix for a memory
corruption happening when intrinsic assignment is used to set a scalar
allocatable polymorphic component of a derived type when the latter
is instanciated as an array of rank > 0.  Just get the dimension
attribute right when using gfc_variable_attr ...

The testcase is an extended version of the reporter's with unlimited
polymorphism, including another simpler one contributed by a friend.
Without the fix, both tests crash with memory corruption of various
kinds.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

If there are no objections, I would like to backport to at least
15-branch.

Thanks,
Harald

From 0899b826f7196f609fc8991456eb728802061318 Mon Sep 17 00:00:00 2001
From: Harald Anlauf <anl...@gmx.de>
Date: Thu, 11 Sep 2025 20:17:31 +0200
Subject: [PATCH] Fortran: fix assignment to allocatable scalar polymorphic
 component [PR121616]

	PR fortran/121616

gcc/fortran/ChangeLog:

	* primary.cc (gfc_variable_attr): Properly set dimension attribute
	from a component ref.

gcc/testsuite/ChangeLog:

	* gfortran.dg/alloc_comp_assign_17.f90: New test.
---
 gcc/fortran/primary.cc                        |  2 +
 .../gfortran.dg/alloc_comp_assign_17.f90      | 96 +++++++++++++++++++
 2 files changed, 98 insertions(+)
 create mode 100644 gcc/testsuite/gfortran.dg/alloc_comp_assign_17.f90

diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index 6df95558bb1..2cb930d83b8 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts)
 
 	if (comp->ts.type == BT_CLASS)
 	  {
+	    dimension = CLASS_DATA (comp)->attr.dimension;
 	    codimension = CLASS_DATA (comp)->attr.codimension;
 	    pointer = CLASS_DATA (comp)->attr.class_pointer;
 	    allocatable = CLASS_DATA (comp)->attr.allocatable;
 	  }
 	else
 	  {
+	    dimension = comp->attr.dimension;
 	    codimension = comp->attr.codimension;
 	    if (expr->ts.type == BT_CLASS && strcmp (comp->name, "_data") == 0)
 	      pointer = comp->attr.class_pointer;
diff --git a/gcc/testsuite/gfortran.dg/alloc_comp_assign_17.f90 b/gcc/testsuite/gfortran.dg/alloc_comp_assign_17.f90
new file mode 100644
index 00000000000..7a659f2e0c0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/alloc_comp_assign_17.f90
@@ -0,0 +1,96 @@
+! { dg-do run }
+! PR fortran/121616
+!
+! Test fix for intrinsic assignment to allocatable scalar polymorphic component
+
+program p
+  call pr121616 ()
+  call test_ts  ()
+end
+
+! Derived from original PR (contributed by Jean Vézina)
+subroutine pr121616 ()
+  implicit none
+  integer :: i
+  type general
+     class(*), allocatable :: x
+  end type general
+  type(general) :: a(4), b(4)
+  ! Intrinsic assignment to a variable of unlimited polymorphic type
+  a(1)%x = 1
+  a(2)%x = 3.14
+  a(3)%x = .true.
+  a(4)%x = 'abc'
+  ! The workaround was to use a structure constructor
+  b(1) = general(1)
+  b(2) = general(3.14)
+  b(3) = general(.true.)
+  b(4) = general('abc') 
+  do i = 1, 4
+     if (.not. allocated (a(i)%x)) stop 10+i
+     if (.not. allocated (b(i)%x)) stop 20+i
+     call prt (a(i)%x, b(i)%x)
+  end do
+  do i = 1, 4
+     deallocate (a(i)%x, b(i)%x)
+  end do
+contains
+  subroutine prt (x, y)
+    class(*), intent(in) :: x, y
+    select type (v=>x)
+    type is (integer)
+       print *,v
+    type is (real)
+       print *,v
+    type is (logical)
+       print *,v
+    type is (character(*))
+       print *,v
+    class default
+       error stop 99
+    end select
+    if (.not. same_type_as (x, y)) stop 30+i
+  end subroutine prt
+end
+
+! Contributed by a friend (private communication)
+subroutine test_ts ()
+  implicit none
+
+  type :: t_inner
+    integer :: i
+  end type
+
+  type :: t_outer
+    class(t_inner), allocatable :: inner
+  end type
+
+  class(t_inner), allocatable :: inner
+  type(t_outer),  allocatable :: outer(:)
+  integer :: i
+
+  allocate(t_inner :: inner)
+  inner% i = 0
+
+  !------------------------------------------------
+  ! Size of outer must be > 1 for the bug to appear
+  !------------------------------------------------
+  allocate(outer(2))
+
+  !------------------------------
+  ! Loop is necessary for the bug
+  !------------------------------
+  do i = 1, size(outer)
+    write(*,*) i
+    !----------------------------------------------------
+    ! Expect intrinsic assignment to polymorphic variable
+    !----------------------------------------------------
+    outer(i)% inner = inner
+    deallocate (outer(i)% inner)
+  end do
+
+  write(*,*) 'Loop DONE'
+  deallocate(outer)
+  deallocate(inner)
+  write(*,*) 'Dellocation DONE'
+end
-- 
2.51.0

Reply via email to