Dear all, this patch fixes a long-standing issue where we did not properly resolve a generic interface when C_LOC or C_FUNLOC were involved. See testcase and PR for details.
(The testcase is an enhanced version of the reporter's.) Regtested on x86_64-pc-linux-gnu. OK for mainline? I'd like to backport this also to 15-branch unless there are objections. Thanks, Harald
From 8398accffc65e825587acd4e74704dc190cf23cd Mon Sep 17 00:00:00 2001 From: Harald Anlauf <[email protected]> Date: Fri, 3 Apr 2026 22:35:48 +0200 Subject: [PATCH] Fortran: fix resolution of generic interface with TYPE(C_PTR) [PR66973] When symbols from the intrinsic module ISO_C_BINDING were USEd indirectly, the resolution of generic interfaces with procedures having dummies with TYPE(C_PTR) or TYPE(C_FUNPTR) could fail when the actual argument was C_LOC() or C_FUNLOC(). Amend checking of actual versus formal procedure arguments to these cases. PR fortran/66973 gcc/fortran/ChangeLog: * interface.cc (gfc_compare_actual_formal): Check that C_LOC and C_FUNLOC from ISO_C_BINDING as actual argument are passed to a dummy argument of matching type C_PTR/C_FUNPTR. gcc/testsuite/ChangeLog: * gfortran.dg/generic_36-1.f90: New test. * gfortran.dg/generic_36-2.f90: New test. --- gcc/fortran/interface.cc | 22 +++++++ gcc/testsuite/gfortran.dg/generic_36-1.f90 | 68 ++++++++++++++++++++++ gcc/testsuite/gfortran.dg/generic_36-2.f90 | 36 ++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/generic_36-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/generic_36-2.f90 diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc index 8a19c14aa78..1cfa4975f16 100644 --- a/gcc/fortran/interface.cc +++ b/gcc/fortran/interface.cc @@ -4127,6 +4127,28 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, goto match; } + /* C_LOC/C_FUNLOC from ISO_C_BINDING as actual argument can only be + passed to a dummy argument of matching type C_PTR/C_FUNPTR. */ + if (a->expr->expr_type == EXPR_FUNCTION + && a->expr->ts.type == BT_VOID + && a->expr->symtree->n.sym + && a->expr->symtree->n.sym->from_intmod == INTMOD_ISO_C_BINDING + && (f->sym->ts.type != BT_DERIVED + || f->sym->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING + || !((a->expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_FUNLOC + && f->sym->ts.u.derived->intmod_sym_id == ISOCBINDING_FUNPTR) + || (a->expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_LOC + && f->sym->ts.u.derived->intmod_sym_id == ISOCBINDING_PTR)))) + { + if (where) + gfc_error ("ISO_C_BINDING function actual argument at %L " + "requires dummy argument %qs to have a matching " + "type from ISO_C_BINDING", + &a->expr->where,f->sym->name); + ok = false; + goto match; + } + match: if (a == actual) na = i; diff --git a/gcc/testsuite/gfortran.dg/generic_36-1.f90 b/gcc/testsuite/gfortran.dg/generic_36-1.f90 new file mode 100644 index 00000000000..d54483f473c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/generic_36-1.f90 @@ -0,0 +1,68 @@ +! { dg-do compile } +! +! PR fortran/66973 - resolution of generic interface with TYPE(C_PTR) + +MODULE H5T + USE ISO_C_BINDING, only: C_LOC, C_PTR, C_NULL_PTR, & + C_FUNLOC, C_FUNPTR, C_NULL_FUNPTR + IMPLICIT NONE + public :: pickone, cnt, test1 + public :: C_LOC, C_PTR, C_NULL_PTR, C_FUNLOC, C_FUNPTR, C_NULL_FUNPTR + private + + INTERFACE pickone + MODULE PROCEDURE pick_f03 ! order matters for the test! + MODULE PROCEDURE pick_funptr + MODULE PROCEDURE pick_f90 + END INTERFACE + + integer :: cnt(3) = 0 + +CONTAINS + + SUBROUTINE pick_f90(int_value) + IMPLICIT NONE + INTEGER, INTENT(IN) :: int_value + PRINT*,'Inside pick_f90' + cnt(1) = cnt(1) + 1 + END SUBROUTINE pick_f90 + + SUBROUTINE pick_f03(value) + IMPLICIT NONE + TYPE(C_PTR), INTENT(IN) :: value + PRINT*,'Inside pick_f03' + cnt(2) = cnt(2) + 1 + END SUBROUTINE pick_f03 + + SUBROUTINE pick_funptr(addr) + IMPLICIT NONE + TYPE(C_FUNPTR), INTENT(IN) :: addr + PRINT*,'Inside pick_funptr' + cnt(3) = cnt(3) + 1 + END SUBROUTINE pick_funptr + + subroutine test1 () + integer :: intval + REAL, TARGET :: val + type(c_ptr) :: ptr + type(c_funptr) :: funptr + procedure(), pointer :: indirect => null() + cnt = 0 + CALL pickone(intval) +! print *, cnt + if (any (cnt /= [1,0,0])) stop 1 + cnt = 0 + CALL pickone(ptr) + CALL pickone(c_null_ptr) + CALL pickone(C_LOC(val)) +! print *, cnt + if (any (cnt /= [0,3,0])) stop 2 + cnt = 0 + CALL pickone(funptr) + CALL pickone(c_null_funptr) + CALL pickone(C_FUNLOC(indirect)) +! print *, cnt + if (any (cnt /= [0,0,3])) stop 3 + end subroutine test1 + +END MODULE H5T diff --git a/gcc/testsuite/gfortran.dg/generic_36-2.f90 b/gcc/testsuite/gfortran.dg/generic_36-2.f90 new file mode 100644 index 00000000000..1467ae6edf2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/generic_36-2.f90 @@ -0,0 +1,36 @@ +! { dg-do run } +! { dg-compile-aux-modules "generic_36-1.f90" } +! { dg-additional-sources generic_36-1.f90 } +! { dg-additional-options "-O2" } +! +! PR fortran/66973 - resolution of generic interface with TYPE(C_PTR) + +PROGRAM main + USE H5T, only: pickone, cnt, test1, & + c_loc, c_ptr, c_null_ptr, & + c_funloc, c_funptr, c_null_funptr + IMPLICIT NONE + integer :: intval + REAL, TARGET :: val + type(c_ptr) :: ptr + type(c_funptr) :: funptr + procedure(), pointer :: indirect => null() + cnt = 0 + call test1 + cnt = 0 + CALL pickone(intval) +! print *, cnt + if (any (cnt /= [1,0,0])) stop 11 + cnt = 0 + CALL pickone(ptr) + CALL pickone(c_null_ptr) + CALL pickone(C_LOC(val)) +! print *, cnt + if (any (cnt /= [0,3,0])) stop 12 + cnt = 0 + CALL pickone(funptr) + CALL pickone(c_null_funptr) + CALL pickone(C_FUNLOC(indirect)) +! print *, cnt + if (any (cnt /= [0,0,3])) stop 13 +END PROGRAM main -- 2.51.0
