Dear maintainers,

The attached patch fixes PR 117303. The reference returned by C_FUNLOC
is assigned to a variable in the added code. Without that,
no reference from the calling subprogram to the argument of C_FUNLOC
was created in the call graph, resulting in an undefined-reference error
with link-time optimization.

The patch was tested using with "check-fortran" on a x86_64-pc-linux-gnu
system. One existing test from gfortran.dg/c_funloc_test_7.f90 failed
as expected due to code-generation change. The generated code was

   cfp = (void (*<T6d>) (void)) nocsub;

but now it became

     void * D.4685;
     D.4685 = (void *) nocsub;
     cfp = (void (*<T6f>) (void)) D.4685;

The test has been modified in accordance with the changes.
Another test, gfortran.dg/c_funloc_test_9.f90, has been converted from
the test case in PR.

        PR fortran/117303

gcc/fortran/ChangeLog:

        * trans-intrinsic.cc (conv_isocbinding_function):
         Assign the reference returned by C_FUNLOC to a variable.

gcc/testsuite/ChangeLog:

        * gfortran.dg/c_funloc_tests_7.f90:
         Updated test due to changed code generation.
        * gfortran.dg/c_funloc_tests_9.f90: New test.

Signed-off-by: Kirill Chilikin <[email protected]>
---

Please see the attached file for the actual patch.
If accepted, please commit the change as I do not have write access.

Regards,
Kirill
From 0577f0452d7fd6973dc30f8aa8d8a3091c1560fa Mon Sep 17 00:00:00 2001
From: Kirill Chilikin <[email protected]>
Date: Sun, 25 Jan 2026 14:43:08 +0700
Subject: [PATCH] fortran: Fix creation of reference to C_FUNLOC argument
 [PR117303]

The reference returned by C_FUNLOC is assigned to a variable. Without that,
no reference from the calling subprogram to the argument of C_FUNLOC
was created in the call graph, resulting in an undefined-reference error
with link-time optimization. Please see PR 117303 for more details.

	PR fortran/117303

gcc/fortran/ChangeLog:

	* trans-intrinsic.cc (conv_isocbinding_function):
        Assign the reference returned by C_FUNLOC to a variable.

gcc/testsuite/ChangeLog:

	* gfortran.dg/c_funloc_tests_7.f90:
        Updated test due to changed code generation.
	* gfortran.dg/c_funloc_tests_9.f90: New test.

Signed-off-by: Kirill Chilikin <[email protected]>
---
 gcc/fortran/trans-intrinsic.cc                |  9 ++++-
 .../gfortran.dg/c_funloc_tests_7.f90          |  2 +-
 .../gfortran.dg/c_funloc_tests_9.f90          | 34 +++++++++++++++++++
 3 files changed, 43 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/c_funloc_tests_9.f90

diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index 722ea933249..cfdd0258241 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -9864,7 +9864,14 @@ conv_isocbinding_function (gfc_se *se, gfc_expr *expr)
       se->expr = gfc_evaluate_now (se->expr, &se->pre);
     }
   else if (expr->value.function.isym->id == GFC_ISYM_C_FUNLOC)
-    gfc_conv_expr_reference (se, arg->expr);
+    {
+      gfc_conv_expr_reference (se, arg->expr);
+      /* The code below is necessary to create a reference from the calling
+	 subprogram to the argument of C_FUNLOC() in the call graph.
+	 Please see PR 117303 for more details. */
+      se->expr = convert (pvoid_type_node, se->expr);
+      se->expr = gfc_evaluate_now (se->expr, &se->pre);
+    }
   else if (expr->value.function.isym->id == GFC_ISYM_C_ASSOCIATED)
     {
       gfc_se arg1se;
diff --git a/gcc/testsuite/gfortran.dg/c_funloc_tests_7.f90 b/gcc/testsuite/gfortran.dg/c_funloc_tests_7.f90
index 7a4464ab552..1e199b4503b 100644
--- a/gcc/testsuite/gfortran.dg/c_funloc_tests_7.f90
+++ b/gcc/testsuite/gfortran.dg/c_funloc_tests_7.f90
@@ -16,6 +16,6 @@ cfp = c_funloc (noCsub)
 call c_f_procpointer (cfp, fint)
 end
 
-! { dg-final { scan-tree-dump-times "cfp =\[^;\]+ nocsub;" 1 "original" } }
+! { dg-final { scan-tree-dump-times "D.\[0-9\]* =\[^;\]+ nocsub;" 1 "original" } }
 ! { dg-final { scan-tree-dump-times "fint =\[^;\]+ cfp;" 1 "original" } }
 
diff --git a/gcc/testsuite/gfortran.dg/c_funloc_tests_9.f90 b/gcc/testsuite/gfortran.dg/c_funloc_tests_9.f90
new file mode 100644
index 00000000000..2ebb951a6fc
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c_funloc_tests_9.f90
@@ -0,0 +1,34 @@
+! { dg-do link }
+! { dg-options "-O1 -flto" }
+! PR 117303
+
+MODULE M1
+  USE, INTRINSIC :: ISO_C_BINDING
+
+  TYPE T
+    TYPE(C_FUNPTR) FUNPTR
+  END TYPE
+
+  TYPE(T), POINTER :: T_POINTER
+
+CONTAINS
+
+  SUBROUTINE SET_FUNPTR(F)
+    TYPE(C_FUNPTR), INTENT(IN) :: F
+    T_POINTER%FUNPTR = F
+  END SUBROUTINE
+
+  SUBROUTINE S1() BIND(C)
+  END SUBROUTINE
+
+END MODULE
+
+PROGRAM TEST
+  USE M1
+  INTEGER(C_INTPTR_T) I
+  ALLOCATE(T_POINTER)
+  ! There was no reference from TEST to S1 in the call graph,
+  ! resulting in undefined-reference error with link-time optimization.
+  CALL SET_FUNPTR(C_FUNLOC(S1))
+  PRINT *, TRANSFER(T_POINTER%FUNPTR, I)
+END PROGRAM
-- 
2.39.5

Reply via email to