Dear all,

this patch appears to fix an almost 10-year old puzzle, where an
attempt was made to prevent some optimizations by declaring
instances of derived types with DTIO as static.  This has the
side-effect that automatic deallocation did not work.

The root cause was a wrong fnspec attribute for the argument
relating to the variable being read.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?
And OK for backport to 16-branch?

Thanks,
Harald

From 6a01f0cc3f37be4d64e4bf5a2b611fa89b6e79ad Mon Sep 17 00:00:00 2001
From: Harald Anlauf <[email protected]>
Date: Thu, 7 May 2026 22:34:52 +0200
Subject: [PATCH] Fortran: fix automatic deallocation with derived type IO
 [PR111952,PR125059]

The implementation of derived type IO wrongly forced allocatable instances
of the DT as static, which prevented automatic deallocation of local
variables.  The motivation was an attempt to prevent optimizations leading
to certain testcase failures.  Howver, the underlying reason of the problem
was a wrong fnspec of _gfortran_transfer_derived that declared the IO
variable as being only read ('r').  Declare the corresponding parameter as
being written ('w').

	PR fortran/111952
	PR fortran/125059

gcc/fortran/ChangeLog:

	* trans-decl.cc (gfc_finish_var_decl): Remove bogus code forcing
	a DT variable with DTIO as static.
	* trans-io.cc (gfc_build_io_library_fndecls): Fix fnspec attribute.

gcc/testsuite/ChangeLog:

	* gfortran.dg/dtio_37.f90: New test.
---
 gcc/fortran/trans-decl.cc             | 10 --------
 gcc/fortran/trans-io.cc               |  2 +-
 gcc/testsuite/gfortran.dg/dtio_37.f90 | 36 +++++++++++++++++++++++++++
 3 files changed, 37 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/dtio_37.f90

diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 4b3f75ced71..dcf4bbfdbf4 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -756,16 +756,6 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym)
 		&& sym->attr.codimension && !sym->attr.allocatable)))
     TREE_STATIC (decl) = 1;
 
-  /* If derived-type variables with DTIO procedures are not made static
-     some bits of code referencing them get optimized away.
-     TODO Understand why this is so and fix it.  */
-  if (!sym->attr.use_assoc
-      && ((sym->ts.type == BT_DERIVED
-           && sym->ts.u.derived->attr.has_dtio_procs)
-	  || (sym->ts.type == BT_CLASS
-	      && CLASS_DATA (sym)->ts.u.derived->attr.has_dtio_procs)))
-    TREE_STATIC (decl) = 1;
-
   /* Treat asynchronous variables the same as volatile, for now.  */
   if (sym->attr.volatile_ || sym->attr.asynchronous)
     {
diff --git a/gcc/fortran/trans-io.cc b/gcc/fortran/trans-io.cc
index a18b2bca6aa..046fb57bcd0 100644
--- a/gcc/fortran/trans-io.cc
+++ b/gcc/fortran/trans-io.cc
@@ -416,7 +416,7 @@ gfc_build_io_library_fndecls (void)
 	integer_type_node, gfc_charlen_type_node);
 
   iocall[IOCALL_X_DERIVED] = gfc_build_library_function_decl_with_spec (
-	get_identifier (PREFIX("transfer_derived")), ". w r ",
+	get_identifier (PREFIX("transfer_derived")), ". w w ",
 	void_type_node, 2, dt_parm_type, pvoid_type_node);
 
   /* Library entry points */
diff --git a/gcc/testsuite/gfortran.dg/dtio_37.f90 b/gcc/testsuite/gfortran.dg/dtio_37.f90
new file mode 100644
index 00000000000..021d0e180b2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dtio_37.f90
@@ -0,0 +1,36 @@
+! { dg-do run }
+! { dg-additional-options "-O2" }
+!
+! PR fortran/125059 - derived type IO and automatic deallocation
+! PR fortran/111952
+
+module m
+  type t
+     integer :: i = 42
+   contains
+     procedure :: w
+     generic :: write(formatted) => w
+  end type t
+contains
+  subroutine w(dtv,unit,iotype,v_list,iostat,iomsg)
+    class(t),        intent(in)    :: dtv
+    integer,         intent(in)    :: unit
+    character(len=*),intent(in)    :: iotype
+    integer,         intent(in)    :: v_list(:)
+    integer,         intent(out)   :: iostat
+    character(len=*),intent(inout) :: iomsg
+    write(unit,*,iostat=iostat,iomsg=iomsg) dtv%i
+  end subroutine w
+end
+
+program p
+  use m
+  call f()
+  call f()
+contains
+  subroutine f()
+    type(t), allocatable :: a(:)
+    allocate (a(1))
+    print *, a(1)
+  end subroutine f
+end
-- 
2.51.0

Reply via email to