Dear all,

this patch fixes a 15/16/17 regression when using the LOC() intrinsic
on SELECT TYPE temporaries, where gfc_is_simply_contiguous could
return false and gfc_conv_array_parameter would create unnecessarily
messy code that lead to an ICE.

I looked at how C_LOC solved this, and adjusted gfc_conv_intrinsic_loc
accordingly.

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

Thanks,
Harald

From 2dcdb2463f89930b8cdd2b15f962bd3df5dd83f7 Mon Sep 17 00:00:00 2001
From: Harald Anlauf <[email protected]>
Date: Sat, 6 Jun 2026 21:59:49 +0200
Subject: [PATCH] Fortran: fix ICE on LOC intrinsic with polymorphic argument
 [PR125606]

The fix for PR122977 improved the gfc_is_simply_contiguous check for
associate variables, but had a side effect when using the LOC() intrinsic
on SELECT TYPE temporaries where gfc_is_simply_contiguous could return
false.  Fall back to simply taking the address of the variable's address.

	PR fortran/125606

gcc/fortran/ChangeLog:

	* trans-intrinsic.cc (gfc_conv_intrinsic_loc): When the argument
	of LOC() is not scalar or known to be simply contiguous, simply
	take the address of the argument array's first element.

gcc/testsuite/ChangeLog:

	* gfortran.dg/loc_3.f90: New test.
---
 gcc/fortran/trans-intrinsic.cc      |  8 ++++++-
 gcc/testsuite/gfortran.dg/loc_3.f90 | 36 +++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gfortran.dg/loc_3.f90

diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index fdb9ddb52ea..a2a6c6979d9 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -9829,9 +9829,15 @@ gfc_conv_intrinsic_loc (gfc_se * se, gfc_expr * expr)
 	gfc_add_data_component (arg_expr);
       gfc_conv_expr_reference (se, arg_expr);
     }
-  else
+  else if (gfc_is_simply_contiguous (arg_expr, false, false))
     gfc_conv_array_parameter (se, arg_expr, true, NULL, NULL, NULL);
+  else
+    {
+      gfc_conv_expr_descriptor (se, arg_expr);
+      se->expr = gfc_conv_descriptor_data_get (se->expr);
+    }
   se->expr = convert (gfc_get_int_type (gfc_index_integer_kind), se->expr);
+  se->expr = gfc_evaluate_now (se->expr, &se->pre);
 
   /* Create a temporary variable for loc return value.  Without this,
      we get an error an ICE in gcc/expr.cc(expand_expr_addr_expr_1).  */
diff --git a/gcc/testsuite/gfortran.dg/loc_3.f90 b/gcc/testsuite/gfortran.dg/loc_3.f90
new file mode 100644
index 00000000000..efc7d0e56e7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loc_3.f90
@@ -0,0 +1,36 @@
+! { dg-do compile }
+! { dg-additional-options "-O1" }
+!
+! PR fortran/125606
+!
+! Derived from Fujitsu testsuite
+! Reported by David Binderman
+
+module m
+  implicit none
+  type ty
+     class(*), allocatable :: c1(:)
+  end type ty
+  type tt
+     class(*), allocatable :: node1(:)
+  end type tt
+  type,extends(tt)::tte
+     class(*), allocatable :: c2e(:)
+  end type tte
+contains
+  subroutine put_addr
+    class(*), allocatable :: t(:)
+    integer :: unit
+    select type (t)
+    class is (tt)
+       select type (p=>t(2)%node1)
+       class is (ty)
+          write (unit) loc(p(2)%c1)
+       end select
+       select type (t)
+       type is (tte)
+          write (7) loc(t(2)%c2e)
+       end select
+    end select
+  end subroutine put_addr
+end module m
-- 
2.51.0

Reply via email to