On 10/20/26 1:36 PM, Mikael Morin wrote:
Le 20/10/2026 à 22:09, Jerry DeLisle a écrit :
Hi Mikael,

Thanks for the review.  You are right on both points.  v2 looks up
'_data', '_vptr' and '_len' in the class container of the CLASS
component they follow, and steps through an implicit '_data' to the
declared type for any other name.  The walk starts at the associate
name's own container when it is CLASS, so both forms after
gfc_fix_class_refs (explicit '_data' or none) are handled the same way.

v1 only got ref->u.c.sym wrong for those refs (the component pointers
were already right), so nothing failed at run time.  The new test
associate_91.f90 uses your foo%class_comp1(4)%class_comp2(:)%bar shape
with a wrong parse-time guess that has the same component names.

That test also exposed a wrong-code bug that trunk has too:
'select type (z => q%a(2)%b(1))' with q an inferred associate name bound
z to the class container instead of its data.  The IS_INFERRED_TYPE
branch in trans_associate_var (from PR87477) took the address of the
container as the data pointer.  v2 also fixes that, with a check that
skips the branch when se.expr points to a class type.

The change from v1 is the reference loop in
gfc_fixup_inferred_type_refs (resolve.cc) and the one-condition change
in trans_associate_var (trans-stmt.cc); the rest is the two tests.

Regression tested on x86_64.

OK for mainline?

Regards,

Jerry

---

fortran: [PR126968] ICE for wrongly guessed inferred ASSOCIATE type

When an ASSOCIATE selector is a function that has not been parsed yet,
primary.cc types the associate name by guessing: it takes the first
accessible derived type that has a component of the name being
referenced.  resolve_assoc_var later corrects the associate name's type
from the resolved selector, and gfc_fixup_inferred_type_refs repaired
the reference chain.

That repair only reset ref->u.c.sym and left ref->u.c.component pointing
into the guessed type.  When the guess was wrong, the component and the
type it is referenced from no longer belonged together, which reached
the backend and gave

   internal compiler error: in gfc_conv_component_ref, at
   fortran/trans-expr.cc:3010

Bind each component reference to the corrected type by looking it up
again by name, walking the whole chain so that nested references are
corrected too.  '_data', '_vptr' and '_len' are looked up in the class
container of the CLASS component they follow; any other name after a
CLASS component follows an implicit '_data'.  A SELECT TYPE selector
that is an element of such a chain was also bound to the class
container instead of its data, because trans_associate_var took the
address of the container as the data pointer.

Assisted-by: Claude Opus 5.5

    PR fortran/126968

gcc/fortran/ChangeLog:

    * resolve.cc (gfc_fixup_inferred_type_refs): Look each component
    reference up again by name in the corrected derived type and
    update both u.c.sym and u.c.component.  Walk the whole reference
    chain instead of stopping at the first component, looking class
    container fields up in the container.
    * trans-stmt.cc (trans_associate_var): Do not use the address of
    a class container as the data of a scalar CLASS selector.

gcc/testsuite/ChangeLog:

    * gfortran.dg/associate_89.f90: New test.
    * gfortran.dg/associate_91.f90: New test.
OK, thanks for it.

Thanks Mikael.

Toon also pointed me to an AI generated review from gcc. That's fascinating.

The attached patch is an updated version to fix a few additional issues. There are some followup todo's from the AI review I will followup on.

OK for mainline?

Jerry

From 8650d33ed8bb1b07970de4dc75a0d593d2ba0bc5 Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Sat, 24 Oct 2026 10:49:03 -0400
Subject: [PATCH v2] fortran: [PR126968] ICE for wrongly guessed inferred
 ASSOCIATE type

When an ASSOCIATE selector is a function that has not been parsed yet,
primary.cc types the associate name by guessing: it takes the first
accessible derived type that has a component of the name being
referenced.  resolve_assoc_var later corrects the associate name's type
from the resolved selector, and gfc_fixup_inferred_type_refs repaired
the reference chain.

That repair only reset ref->u.c.sym and left ref->u.c.component pointing
into the guessed type.  When the guess was wrong, the component and the
type it is referenced from no longer belonged together, which reached
the backend and gave

  internal compiler error: in gfc_conv_component_ref, at
  fortran/trans-expr.cc:3010

Bind each component reference to the corrected type by looking it up
again by name, walking the whole chain so that nested references are
corrected too.  After a CLASS component, a '_data', '_vptr' or '_len'
reference is looked up in that component's class container, and any
other reference is bound to its declared type, since the '_data'
reference in between can be explicit or implicit.  Rebinding stops at
'_vptr' and '_len'.

Assisted-by: Claude Opus 5.5

	PR fortran/126968

gcc/fortran/ChangeLog:

	* resolve.cc (gfc_fixup_inferred_type_refs): Look each component
	reference up again by name in the corrected derived type and
	update both u.c.sym and u.c.component.  Walk the whole reference
	chain instead of stopping at the first component.  Look up
	'_data', '_vptr' and '_len' in the class container of the
	preceding CLASS component.

gcc/testsuite/ChangeLog:

	* gfortran.dg/associate_89.f90: New test.
	* gfortran.dg/associate_91.f90: New test.
---
 gcc/fortran/resolve.cc                     | 65 +++++++++++++++---
 gcc/testsuite/gfortran.dg/associate_89.f90 | 56 ++++++++++++++++
 gcc/testsuite/gfortran.dg/associate_91.f90 | 78 ++++++++++++++++++++++
 3 files changed, 189 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/associate_89.f90
 create mode 100644 gcc/testsuite/gfortran.dg/associate_91.f90

diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 64388fb75c0..ab0002a9d13 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -7007,7 +7007,7 @@ void
 gfc_fixup_inferred_type_refs (gfc_expr *e)
 {
   gfc_ref *ref, *new_ref;
-  gfc_symbol *sym, *derived;
+  gfc_symbol *sym, *derived, *dt, *container;
   gfc_expr *target;
   sym = e->symtree->n.sym;
 
@@ -7108,17 +7108,62 @@ gfc_fixup_inferred_type_refs (gfc_expr *e)
 	}
     }
 
-  /* Proceed as far as the first component reference and ensure that the
-     correct derived type is being used.  */
+  /* The type used to build the component references at parse time was only
+     a guess, so they can point into a different derived type that happens
+     to have a component of the same name.  Bind each one by name to the
+     corrected type.  */
+  dt = derived;
+  container = sym->ts.type == BT_CLASS ? sym->ts.u.derived : NULL;
   for (ref = e->ref; ref; ref = ref->next)
-    if (ref->type == REF_COMPONENT)
-      {
-	if (ref->u.c.component->name[0] != '_')
-	  ref->u.c.sym = derived;
-	else
-	  ref->u.c.sym = sym->ts.u.derived;
+    {
+      gfc_component *c;
+
+      if (ref->type != REF_COMPONENT)
+	continue;
+
+      /* '_data', '_vptr' and '_len' are fields of the preceding class
+	 container; 'dt' already is the declared type that follows '_data'.  */
+      if (ref->u.c.component->name[0] == '_')
+	{
+	  if (!container)
+	    break;
+	  c = gfc_find_component (container, ref->u.c.component->name,
+				  true, true, NULL);
+	  if (!c)
+	    break;
+	  ref->u.c.sym = container;
+	  ref->u.c.component = c;
+	  container = NULL;
+	  if (strcmp (c->name, "_data") != 0)
+	    break;
+	  continue;
+	}
+
+      if (!dt)
 	break;
-      }
+
+      c = gfc_find_component (dt, ref->u.c.component->name, true, true, NULL);
+      if (!c)
+	{
+	  gfc_error ("%qs at %L is not a member of the %qs structure",
+		     ref->u.c.component->name, &e->where, dt->name);
+	  return;
+	}
+
+      ref->u.c.sym = dt;
+      ref->u.c.component = c;
+
+      container = NULL;
+      if (c->ts.type == BT_DERIVED)
+	dt = c->ts.u.derived;
+      else if (c->ts.type == BT_CLASS && CLASS_DATA (c))
+	{
+	  container = c->ts.u.derived;
+	  dt = CLASS_DATA (c)->ts.u.derived;
+	}
+      else
+	dt = NULL;
+    }
 
   /* Verify that the type inference mechanism has not introduced a spurious
      array reference.  This can happen with an associate name, whose selector
diff --git a/gcc/testsuite/gfortran.dg/associate_89.f90 b/gcc/testsuite/gfortran.dg/associate_89.f90
new file mode 100644
index 00000000000..75a48b63e30
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_89.f90
@@ -0,0 +1,56 @@
+! { dg-do run }
+! PR fortran/126968
+! ICE in gfc_conv_component_ref when the type of an associate name, whose
+! selector is a function that has not yet been parsed, is guessed wrongly.
+! The guess is the first accessible type with a component of the right name,
+! so 'wrong_t' is picked and has to be corrected during resolution.
+!
+module m
+  type :: wrong_t
+     integer :: x = 1
+     integer :: pad = 0
+  end type
+  type :: right_t
+     real :: junk = 0.0
+     real :: x = 2.5
+  end type
+  type :: outer_t
+     type(right_t) :: c
+  end type
+end module
+
+program p
+  use m
+  implicit none
+  real :: r, ra(3)
+
+  associate (q => scalar_fcn ())
+    r = q%x
+  end associate
+  if (abs (r - 2.5) > 1.0e-6) stop 1
+
+  associate (q => array_fcn ())
+    ra = q(:)%x
+  end associate
+  if (any (abs (ra - 2.5) > 1.0e-6)) stop 2
+
+  associate (q => nested_fcn ())
+    r = q%c%x
+  end associate
+  if (abs (r - 2.5) > 1.0e-6) stop 3
+
+contains
+
+  function scalar_fcn () result (y)
+    type(right_t) :: y
+  end function
+
+  function array_fcn () result (y)
+    type(right_t) :: y(3)
+  end function
+
+  function nested_fcn () result (y)
+    type(outer_t) :: y
+  end function
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/associate_91.f90 b/gcc/testsuite/gfortran.dg/associate_91.f90
new file mode 100644
index 00000000000..05cecc48a08
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_91.f90
@@ -0,0 +1,78 @@
+! { dg-do run }
+! PR fortran/126968
+! Component references through nested CLASS components of an associate name
+! whose type was guessed wrongly ('wrong_t').  The chain can carry explicit
+! or implicit '_data' references after each CLASS component.
+!
+module m
+  type :: wrong_t
+     integer :: c1 = 1
+  end type
+  type :: leaf_t
+     integer :: bar = 0
+  end type
+  type, extends (leaf_t) :: leaf2_t
+     integer :: baz = 7
+  end type
+  type :: mid_t
+     real :: junk = 0.0
+     class(leaf_t), allocatable :: c2(:)
+  end type
+  type :: outer_t
+     class(mid_t), allocatable :: c1(:)
+  end type
+contains
+  subroutine fill (y)
+    class(outer_t) :: y
+    integer :: k
+    allocate (mid_t :: y%c1(5))
+    do k = 1, 5
+      allocate (leaf2_t :: y%c1(k)%c2(3))
+      y%c1(k)%c2(:)%bar = [10*(k-3)+1, 10*(k-3)+2, 10*(k-3)+3]
+    end do
+  end subroutine
+end module
+
+program p
+  use m
+  implicit none
+  integer :: i, ia(3)
+
+  associate (q => tfcn ())
+    ia = q%c1(4)%c2(:)%bar
+  end associate
+  if (any (ia /= [11, 12, 13])) stop 1
+
+  associate (q => cfcn ())
+    ia = q%c1(4)%c2(:)%bar
+  end associate
+  if (any (ia /= [11, 12, 13])) stop 2
+
+  associate (q => cfcn ())
+    i = q%c1(4)%c2(2)%bar
+  end associate
+  if (i /= 12) stop 3
+
+  associate (q => tfcn ())
+    if (.not. same_type_as (q%c1(4)%c2, leaf2_t ())) stop 4
+    select type (z => q%c1(4)%c2)
+      type is (leaf2_t)
+        if (any (z%baz /= 7)) stop 5
+      class default
+        stop 6
+    end select
+  end associate
+
+contains
+
+  function tfcn () result (y)
+    type(outer_t) :: y
+    call fill (y)
+  end function
+
+  function cfcn () result (y)
+    class(outer_t), allocatable :: y
+    allocate (y)
+    call fill (y)
+  end function
+end program
-- 
2.56.0

Reply via email to