bug9-class-is-kind-ice.f90:35:16:

   35 |       class is (base(8, *))     ! distinct guards - C1168 permits this
      |                1
Error: Double CLASS IS block in SELECT TYPE statement at (1)

bug10-unlimited-poly-alloc-len.f90 failed in runtime:
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
....etc.,etc.....

The fixes are inter-dependent and so come in a single patch.

The chunks in gfortran.h and resolve.cc are sufficiently explained in
the ChangeLog entries.

The first three chunks in trans-stmt.cc convert the PDT structure
constructor, emanating from the ALLOCATE typespec, convert it to a
type parameter list and append it to the initialization expression.

Chunk 4, then exploits the so appended initialization expression or if
it is not available and the MOLD expr3 is a PDT structure constructor,
does a likewise conversion of expr3. The parameterized components are
then allocated and the result used as the rhs in the assignment to the
allocated expression.

Passes regtesting on FC44/x86_64. OK for mainline.

Cheers

Paul
From 2525041041d9396ab9097b5cf522854355dbfd60 Mon Sep 17 00:00:00 2001
From: Paul Thomas <[email protected]>
Date: Wed, 7 Oct 2026 08:37:44 +0100
Subject: [PATCH] Fortran: [meta-bug] [PDT] Parameterized derived type errors
 [PR82173]

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

gcc/fortran
	PR fortran/82173
	* gfortran.h : Add prototype for gfc_get_temp_from_expr.
	* resolve.cc (resolve_allocate_deallocate): The default init.
	expression should not be used for MOLD expression3 in the cases
	of PDTs and PDT classes.
	(resolve_select_type): Use both the hash values and names to
	distiguish CLASS IS selectors.
	(get_temp_from_expr): Call the static version from gfc_get_temp
	_from_expr.
	* trans-stmt.cc : Inclode constructor.h.
	(convert_structure_to_type_list): New function to do what the
	name says.
	(allocate_get_initializer): WHen the allocate statement has a
	typespec and the init statement is a PDT structure, convert it
	using the new function and attach the parm list to the init
	expression.
	(gfc_trans_allocate): As well as the init expression returned
	allocate_get_initializer, branch on a mold expr3 being an PDT
	structure expression. If the init_expr is NULL, copy expr3 and,
	if necessary, use the new function to add a param_list. Then,
	if the init_expr is a PDT with a param_list, allocate the
	paramaterized components.

gcc/testsuite/
	PR fortran/82173
	* gfortran.dg/pdt_bug9.f90: New test.
	* gfortran.dg/pdt_bug10.f90: New test.
---
 gcc/fortran/gfortran.h                  |  1 +
 gcc/fortran/resolve.cc                  | 17 ++++++-
 gcc/fortran/trans-stmt.cc               | 65 +++++++++++++++++++++++--
 gcc/testsuite/gfortran.dg/pdt_bug10.f90 | 21 ++++++++
 gcc/testsuite/gfortran.dg/pdt_bug9.f90  | 42 ++++++++++++++++
 5 files changed, 141 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/pdt_bug10.f90
 create mode 100644 gcc/testsuite/gfortran.dg/pdt_bug9.f90

diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index a1badd0bde8..19f2b259164 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -4228,6 +4228,7 @@ extern int gfc_do_concurrent_flag;
 const char* gfc_lookup_function_fuzzy (const char *, gfc_symtree *);
 bool gfc_pure_function (gfc_expr *e, const char **name);
 bool gfc_implicit_pure_function (gfc_expr *e);
+gfc_expr* gfc_get_temp_from_expr (gfc_expr *, gfc_namespace *, bool);
 
 /* coarray.cc */
 void gfc_coarray_rewrite (gfc_namespace *);
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 67eaea64c9b..e7caf9dd747 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -10065,6 +10065,7 @@ done_errmsg:
 	 once here.  */
       if (code->expr3 && code->expr3->mold
 	  && code->expr3->ts.type == BT_DERIVED
+	  && !IS_PDT (code->expr3) && !IS_CLASS_PDT (code->expr3)
 	  && !(code->expr3->ref && code->expr3->ref->type == REF_ARRAY))
 	{
 	  /* Default initialization via MOLD (non-polymorphic).  */
@@ -11607,16 +11608,20 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns)
 	      swapped = false;
 	      for (c1 = &class_is; (*c1) && (*c1)->block; c1 = &((*c1)->block))
 		{
+#define C1_DERIVED (*c1)->ext.block.case_list->ts.u.derived
+#define C2_DERIVED c2->ext.block.case_list->ts.u.derived
 		  c2 = (*c1)->block;
 		  /* F03:C817 (check for doubles).  */
-		  if ((*c1)->ext.block.case_list->ts.u.derived->hash_value
-		      == c2->ext.block.case_list->ts.u.derived->hash_value)
+		  if (C1_DERIVED->hash_value == C2_DERIVED->hash_value
+		      && !strcmp (C2_DERIVED->name, C1_DERIVED->name))
 		    {
 		      gfc_error ("Double CLASS IS block in SELECT TYPE "
 				 "statement at %L",
 				 &c2->ext.block.case_list->where);
 		      return;
 		    }
+#undef C1_DERIVED
+#undef C2_DERIVED
 		  if ((*c1)->ext.block.case_list->ts.u.derived->attr.extension
 		      < c2->ext.block.case_list->ts.u.derived->attr.extension)
 		    {
@@ -13658,6 +13663,14 @@ get_temp_from_expr (gfc_expr *e, gfc_namespace *ns,
 }
 
 
+gfc_expr*
+gfc_get_temp_from_expr (gfc_expr *e, gfc_namespace *ns,
+			bool allocatable = false)
+{
+  return get_temp_from_expr (e, ns, allocatable);
+}
+
+
 /* Helper function to take an argument in a subroutine call with a dependency
    on another argument, copy it to an allocatable temporary and use the
    temporary in the call expression. The new code is embedded in a block to
diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc
index 2a87176ffa9..9ad8342605a 100644
--- a/gcc/fortran/trans-stmt.cc
+++ b/gcc/fortran/trans-stmt.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "trans-const.h"
 #include "trans-descriptor.h"
 #include "dependency.h"
+#include "constructor.h"
 
 typedef struct iter_info
 {
@@ -6599,6 +6600,35 @@ gfc_trans_exit (gfc_code * code)
 }
 
 
+/* Add the type parameter list to a PDT structure expression.  */
+
+static void
+convert_structure_to_type_list (gfc_symbol *derived, gfc_expr *init)
+{
+  gfc_constructor *ctr;
+  gfc_component *cmp;
+  gfc_actual_arglist *parms = NULL;
+  ctr = gfc_constructor_first (init->value.constructor);
+  cmp = derived->components;
+  init->param_list = NULL;
+  for (; ctr && cmp; ctr = gfc_constructor_next (ctr), cmp = cmp->next)
+    {
+      if (!cmp->attr.pdt_kind && !cmp->attr.pdt_len)
+	break;
+      if (!init->param_list)
+	init->param_list = parms = gfc_get_actual_arglist ();
+      else
+	{
+	  parms->next = gfc_get_actual_arglist ();
+	  parms = parms->next;
+	}
+      parms->name = cmp->name;
+      parms->spec_type = ctr->expr ? SPEC_EXPLICIT : SPEC_ASSUMED;
+      parms->expr = gfc_copy_expr (ctr->expr);
+    }
+}
+
+
 /* Get the initializer expression for the code and expr of an allocate.
    When no initializer is needed return NULL.  */
 
@@ -6612,7 +6642,13 @@ allocate_get_initializer (gfc_code * code, gfc_expr * expr)
   if (code->ext.alloc.ts.type == BT_DERIVED
       && (code->ext.alloc.ts.u.derived->attr.alloc_comp
 	  || gfc_has_default_initializer (code->ext.alloc.ts.u.derived)))
-    return gfc_default_initializer (&code->ext.alloc.ts);
+    {
+      gfc_expr *init = gfc_default_initializer (&code->ext.alloc.ts);
+      if (code->ext.alloc.ts.u.derived->attr.pdt_type
+	  && init && init->expr_type == EXPR_STRUCTURE)
+	convert_structure_to_type_list (code->ext.alloc.ts.u.derived, init);
+      return init;
+    }
 
   if (gfc_bt_struct (expr->ts.type)
       && (expr->ts.u.derived->attr.alloc_comp
@@ -7708,15 +7744,38 @@ gfc_trans_allocate (gfc_code * code, gfc_omp_namelist *omp_allocate)
 	  if (tmp != NULL_TREE)
 	    gfc_add_expr_to_block (&block, tmp);
 	}
-      else if ((init_expr = allocate_get_initializer (code, expr)))
+      else if ((init_expr = allocate_get_initializer (code, expr))
+	       || (code->expr3 && code->expr3->expr_type == EXPR_STRUCTURE
+		   && code->expr3->mold && IS_PDT (code->expr3)))
 	{
 	  /* Use class_init_assign to initialize expr.  */
 	  gfc_code *ini;
 	  int realloc_lhs = flag_realloc_lhs;
+
 	  ini = gfc_get_code (EXEC_INIT_ASSIGN);
 	  ini->expr1 = gfc_expr_to_initialize (expr);
-	  ini->expr2 = init_expr;
 	  flag_realloc_lhs = 0;
+
+	  if (init_expr == NULL)
+	    {
+	      init_expr = gfc_copy_expr (code->expr3);
+	      if (!init_expr->param_list)
+		convert_structure_to_type_list (code->expr3->ts.u.derived,
+						init_expr);
+	    }
+
+	  if (IS_PDT (init_expr) && init_expr->param_list)
+	    {
+	      gfc_expr *var;
+	      tree decl;
+	      var = gfc_get_temp_from_expr (init_expr, gfc_current_ns, false);
+	      decl = gfc_get_symbol_decl (var->symtree->n.sym);
+	      tmp = gfc_allocate_pdt_comp (init_expr->ts.u.derived, decl,
+					   0, init_expr->param_list);
+	      gfc_add_expr_to_block (&block, tmp);
+	      gfc_replace_expr (init_expr, var);
+	    }
+	  ini->expr2 = init_expr;
 	  tmp= gfc_trans_init_assign (ini);
 	  flag_realloc_lhs = realloc_lhs;
 	  gfc_free_statements (ini);
diff --git a/gcc/testsuite/gfortran.dg/pdt_bug10.f90 b/gcc/testsuite/gfortran.dg/pdt_bug10.f90
new file mode 100644
index 00000000000..d5c277f895c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_bug10.f90
@@ -0,0 +1,21 @@
+! { dg-do run }
+module m2
+  type :: base(k, n)
+    integer, kind :: k = 4
+    integer, len :: n = 1
+    real(k) :: v(n)
+  end type
+end module
+program i2
+  use m2
+  class(*), allocatable :: u
+  allocate (base(4, 3) :: u)
+!  allocate (u, source = base(4, 3)([1,2,3])) ! Was OK
+  select type (u)
+  type is (base(4, *))
+    if (u%n /= 3) stop 1
+    if (size (u%v) /= 3) stop 2
+  class default
+    stop 3
+  end select
+end program
diff --git a/gcc/testsuite/gfortran.dg/pdt_bug9.f90 b/gcc/testsuite/gfortran.dg/pdt_bug9.f90
new file mode 100644
index 00000000000..73ebf12d3f8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_bug9.f90
@@ -0,0 +1,42 @@
+! { dg-do run }
+! See attachment to PR82173 comment 10 - reproducers/bug9-class-is-kind-ice.f90
+module mj
+  type :: base(k, n)
+    integer, kind :: k = 4
+    integer, len :: n = 1
+    real(k) :: v(n)
+  end type
+end module
+program j1
+  use mj
+!  type(base(16,4)) :: mld
+  class(*), allocatable :: u
+  allocate (base(4, 3) :: u) ! This failed
+  call selector (u)
+  deallocate (u) 
+  allocate (base(8, 5) :: u) ! This failed
+  call selector (u)
+  deallocate (u)
+  allocate (u, source = base(4, 3)([1,2,3]))
+  call selector (u)
+  deallocate (u)
+  allocate (u, mold = base(16, 4)([1.,2.,3.,4.])) ! This failed
+  call selector (u)
+  u = base(4, 3)([1,2,3])
+  call selector (u)
+contains
+  subroutine selector (u)
+    class(*), allocatable :: u
+    if (.not.allocated (u)) return
+    select type (u)
+      class is (base(4, *))     ! distinct kind parameter values are
+        if (size (u%v, 1) /= 3) stop 1
+        if (kind (u%v) /= 4) stop 2
+      class is (base(8, *))     ! distinct guards - C1168 permits this
+        if (size(u%v, 1) /= 5) stop 3
+        if (kind (u%v) /= 8) stop 4
+      class is (base(16, *))    ! ditto
+        if (size(u%v, 1) /= 4) stop 5
+    end select
+  end
+end program
-- 
2.55.0

Reply via email to