Hello All,

The Jerry/Claude review revealed:
Verdict: Blocker: new ICEs for MOLD= an assumed-LEN dummy, a
deferred-LEN allocatable, or a component. Blocker: a module procedure
result in a submodule now ICEs. There is no test for bug23.

These issues are all fixed in the attached patch, which also passes
regression testing.

OK for mainline?

Regards

Paul

On Thu, 8 Oct 2026 at 13:36, Paul Richard Thomas
<[email protected]> wrote:
>
> bug16-mold-loses-len.f90 failed to give the correct result because
> ALLOCATE with MOLD= did not propagate the LEN parameter.
>
> The ChangeLog provides quite enough explanation of what the patch does.
>
> Passes regtesting on FC44/x86_64. OK for mainline.
>
> Cheers
>
> Paul
From 4eba7bd6e4e03d08c61519a08190a99f7d45798a Mon Sep 17 00:00:00 2001
From: Paul Thomas <[email protected]>
Date: Thu, 22 Oct 2026 12:57:32 +0100
Subject: [PATCH] Fortran: [PDT] (11/16) Parameterized derived type errors
 [PR82173]

2026-10-22  Paul Thomas  <[email protected]>

gcc/fortran
	PR fortran/82173
	* decl.cc (get_proc_name): Transfer the interface result parms
	to the stashed procedure decl 'sym->tlink'...
	(gfc_match_submod_proc): ... so that they can be copied to the
	final procedure symbol.
	* resolve.cc (resolve_pdt): Finally, transfer the parms to the
	explicit result, if present.
	* trans-decl.cc (gfc_trans_deferred_vars): If a PDT procedure
	result has no default initializer or it is in a submodule then
	allocate the parameterized components using its param_list if
	present.
	* trans-stmt.cc (gfc_trans_allocate): If a PDT MOLD expr3 is a
	variable, use the symbol's param_list. Assert that there is a
	param_list.

gcc/testsuite/
	PR fortran/82173
	* gfortran.dg/pdt_bug16.f90: New test.
	* gfortran.dg/pdt_bug23.f90: New test.
---
 gcc/fortran/decl.cc                     | 11 +++
 gcc/fortran/resolve.cc                  |  9 ++-
 gcc/fortran/trans-decl.cc               |  5 +-
 gcc/fortran/trans-stmt.cc               |  6 ++
 gcc/testsuite/gfortran.dg/pdt_bug16.f90 | 31 ++++++++
 gcc/testsuite/gfortran.dg/pdt_bug23.f90 | 98 +++++++++++++++++++++++++
 6 files changed, 158 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/pdt_bug16.f90
 create mode 100644 gcc/testsuite/gfortran.dg/pdt_bug23.f90

diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 63d4973c018..88bdb54dd2f 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -1378,6 +1378,7 @@ get_proc_name (const char *name, gfc_symbol **result, bool module_fcn_entry)
 
   if (sym->attr.module_procedure && sym->attr.if_source == IFSRC_IFBODY)
     {
+      gfc_actual_arglist *parms = NULL;
       /* Create a partially populated interface symbol to carry the
 	 characteristics of the procedure and the result.  */
       sym->tlink = gfc_new_symbol (name, sym->ns);
@@ -1386,6 +1387,13 @@ get_proc_name (const char *name, gfc_symbol **result, bool module_fcn_entry)
       if (sym->attr.dimension)
 	sym->tlink->as = gfc_copy_array_spec (sym->as);
 
+      /* The result parameters coming from the interface have to be copied
+	 to the procedure symbol itself because of the modifications to
+	 the result further downstream. This is required in trans-decl.cc
+	 when the result is initialized.  */
+      if (sym->result && IS_PDT (sym->result) && sym->result->param_list)
+	  parms = gfc_copy_actual_arglist (sym->result->param_list);
+
       /* Ideally, at this point, a copy would be made of the formal
 	 arguments and their namespace. However, this does not appear
 	 to be necessary, albeit at the expense of not being able to
@@ -1394,11 +1402,13 @@ get_proc_name (const char *name, gfc_symbol **result, bool module_fcn_entry)
       if (sym->result && sym->result != sym)
 	{
 	  sym->tlink->result = sym->result;
+	  sym->tlink->param_list = parms;
 	  sym->result = NULL;
 	}
       else if (sym->result)
 	{
 	  sym->tlink->result = sym->tlink;
+	  sym->tlink->param_list = parms;
 	}
     }
   else if (sym && !sym->gfc_new
@@ -10811,6 +10821,7 @@ gfc_match_submod_proc (void)
 	      st->n.sym = sym->result;
 	      sym->result->refs++;
 	    }
+	  sym->param_list = gfc_copy_actual_arglist (sym->tlink->param_list);
 	}
       else
 	sym->result = sym;
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 1167fc2a1a9..ac83544edd6 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -18612,6 +18612,14 @@ resolve_pdt (gfc_symbol* sym)
 
   gcc_assert (derived->attr.pdt_type);
 
+  /* Now that the result symbol has been corrected for these module
+     procedures, we can transfer the param_list from the proc sym.  */
+  if (sym->abr_modproc_decl && sym->result && sym != sym->result)
+    {
+      sym->result->param_list = sym->param_list;
+      sym->param_list = NULL;
+    }
+
   for (param = sym->param_list; param; param = param->next)
     {
       c = gfc_find_component (derived, param->name, false, true, NULL);
@@ -18633,7 +18641,6 @@ resolve_pdt (gfc_symbol* sym)
 		   "or ALLOCATABLE attribute",
 		   sym->name, &sym->declared_at,
 		   param->name);
-
     }
 
   if (!const_len_exprs
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 5d0d9ba1fda..c4627b39895 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -5070,7 +5070,10 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
 
   if (sym && !sym->attr.allocatable && !sym->attr.pointer
       && sym->attr.referenced
-      && IS_PDT (sym) && !gfc_has_default_initializer (sym->ts.u.derived))
+      && IS_PDT (sym)
+      && sym->param_list
+      && (!gfc_has_default_initializer (sym->ts.u.derived)
+	  || proc_sym->attr.used_in_submodule))
     {
       gfc_init_block (&tmpblock);
       tmp = gfc_allocate_pdt_comp (sym->ts.u.derived,
diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc
index 65bf2ec9d93..a96aef4d59f 100644
--- a/gcc/fortran/trans-stmt.cc
+++ b/gcc/fortran/trans-stmt.cc
@@ -7754,10 +7754,16 @@ gfc_trans_allocate (gfc_code * code, gfc_omp_namelist *omp_allocate)
 
 	  if (code->expr3 && code->expr3->param_list)
 	    param_list = code->expr3->param_list;
+	  else if (code->expr3 && code->expr3->mold
+		   && code->expr3->expr_type == EXPR_VARIABLE)
+	    param_list = code->expr3->symtree->n.sym->param_list;
 	  else if (expr->param_list)
 	    param_list = expr->param_list;
 	  else
 	    param_list = expr->symtree->n.sym->param_list;
+
+	  gcc_assert (param_list);
+
 	  /* For array allocations the allocate-shape-spec expression has
 	     rank 0 even though the symbol is an array.  Use the rank from
 	     the array descriptor when se.expr is a GFC descriptor so that
diff --git a/gcc/testsuite/gfortran.dg/pdt_bug16.f90 b/gcc/testsuite/gfortran.dg/pdt_bug16.f90
new file mode 100644
index 00000000000..1b457620568
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_bug16.f90
@@ -0,0 +1,31 @@
+! { dg-do run }
+! ALLOCATE with MOLD= did not propagate the LEN parameter; SOURCE= does.
+! See attachment to PR82173 comment 10 - ~/reducers/bug16-mold-loses-len.f90
+program p
+  type :: t(n)
+    integer, len :: n = 1
+    integer :: v(n)
+  end type
+  type(t(:)), allocatable :: viaSource, viaMold
+  type(t(5)) :: src1
+  type(t(7)) :: src2
+  src1%v = 1
+  src2%v = 2
+  allocate (viaSource, source=src1)
+  allocate (viaMold, mold=src1)
+  if (viaSource%n /= viaMold%n) stop 1
+  if (size (viaSource%v, 1) /= size (viaMold%v, 1)) stop 2
+!
+! Do it again with a different value for n
+!
+  deallocate (viaSource, viaMold)
+  allocate (viaSource, source=src2)
+  allocate (viaMold, mold=src2)
+  viaMold%v = 2
+  if (viaSource%n /= 7) stop 3
+  if (viaSource%n /= viaMold%n) stop 4
+  if (size (viaMold%v, 1) /= 7) stop 5
+  if (size (viaSource%v, 1) /= size (viaMold%v, 1)) stop 6
+  if (sum (viaSource%v) /= sum (viaMold%v)) stop 7
+  deallocate (viaSource, viaMold)
+end program
diff --git a/gcc/testsuite/gfortran.dg/pdt_bug23.f90 b/gcc/testsuite/gfortran.dg/pdt_bug23.f90
new file mode 100644
index 00000000000..38ed4d842b3
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_bug23.f90
@@ -0,0 +1,98 @@
+! { dg-do run }
+! ALLOCATE with MOLD= did not propagate the LEN parameter; SOURCE= does.
+! The abreviated form of MODULE PROCEDURE was found not to work and has been fixed.
+! See attachment to PR82173 comment 10 - ~/reducers/bug23-submodule-pdt-result.f90
+module s_m
+  type :: t(n)
+    integer, len :: n = 1
+    real :: v(n)
+  end type
+  interface
+! First test the MODULE FUNCTIONs
+    module function make (arg1) result (r)  ! Explicit result using integer arg
+      integer, intent(in) :: arg1
+      type(t(arg1)) :: r
+    end function
+    module function make2 (arg1) result (r) ! Explicit result using deferred len arg
+      type(t(:)), allocatable :: arg1
+      type(t(arg1%n)) :: r
+    end function
+    module function make3 (arg1) result (r) ! Explicit result using assumed len arg
+      type(t(*)) :: arg1
+      type(t(arg1%n)) :: r
+    end function
+! Then the MODULE PROCEDUREs
+    module function make4 (arg1) result (r) ! Explicit result using integer arg
+      integer, intent(in) :: arg1
+      type(t(arg1)) :: r
+    end function
+    module function make5 (arg1) result (r) ! Explicit result using assumed len arg
+      type(t(*)), intent(in) :: arg1
+      type(t(arg1%n)) :: r
+    end function
+    module function make6 (arg1) result (r) ! Explicit result using deferred len arg
+      type(t(:)), allocatable, intent(in) :: arg1
+      type(t(arg1%n)) :: r
+    end function
+  end interface
+end module
+
+submodule (s_m) s_impl
+contains
+! test module functions
+  module function make (arg1) result (r)
+    integer, intent(in) :: arg1
+    type(t(arg1)) :: r
+    r%v = 2.0
+  end function
+  module function make2 (arg1) result (r)
+    type(t(:)), allocatable :: arg1
+    type(t(arg1%n)) :: r
+    if (allocated (arg1)) then
+      r = arg1
+    else
+      allocate (arg1, source = t(5)([1.,2.,3.,4.,5.]))
+      r = arg1
+    end if
+  end function
+  module function make3 (arg1) result (r)
+    type(t(*)) :: arg1
+    type(t(arg1%n)) :: r
+    r%v = arg1%v - 5
+  end function
+
+! Test module procedures
+  module procedure make4
+    integer :: i
+    r%v = [(real (i), i = 1, size (r%v, 1))]
+  end procedure
+  module procedure make5
+    r%v = 3.0 * arg1%v
+  end procedure
+  module procedure make6
+    if (.not.allocated (arg1)) stop 99
+    r%v = arg1%v / 3.0
+  end procedure
+end submodule
+
+program v3
+  use s_m
+  type(t(5)) :: a
+  type(t(:)), allocatable :: b
+  integer :: i
+  a = make (5)
+  IF (a%n /= 5) STOP 1
+  IF (INT (sum (a%v)) /= 10) STOP 2
+  allocate (b, source = t(5)([1.,2.,3.,4.,5.]))
+  a = make2 (b)
+  if (int (sum (a%v)) /= 15) stop 3
+  b = make3 (a)
+  if (int (sum (b%v)) /= -10) stop 4
+  b = make4 (10)
+  if (any (int (b%v) /= [(i, i = 1, b%n)])) stop 5
+  b = make5 (a)
+  if (any (int (b%v) /= 3 * int (a%v))) stop 6
+  b = make6 (b)
+  if (int (sum (b%v)) /= 15) stop 7
+  deallocate (b)
+end program
-- 
2.56.0

Reply via email to