Hi all, the attached patch fixes a rather strange 12/13/14/15 regression. When walking through the list of procedures in an interface to find the matching one, the code could remember an inferred type from a false module procedure within the same interface if and only if optional arguments were in the procedure declarations, and the procedure call did not provide an actual argument for an optional one. An inferred type could then leak into gfc_conv_procedure_call and pretend a wrong type for the dummy.
(This bug appears to be related to a code refactoring during 12-development and is not present in 11-releases.) The simple and obvious solution is to use the type of the formal, as inferred types are only relevant when there is no explicit interface. Regtested on x86_64-pc-linux-gnu. OK for mainline? As this is a regression, I would like to backport this as appropriate. Thanks, Harald
From 468ca59fd29ad629198dc2ada0d73e7898588edc Mon Sep 17 00:00:00 2001 From: Harald Anlauf <anl...@gmx.de> Date: Tue, 8 Apr 2025 22:30:15 +0200 Subject: [PATCH] Fortran: fix issue with impure elemental subroutine and interface [PR119656] PR fortran/119656 gcc/fortran/ChangeLog: * interface.cc (gfc_compare_actual_formal): Fix front-end memleak when searching for matching interfaces. * trans-expr.cc (gfc_conv_procedure_call): If there is a formal dummy corresponding to an absent argument, use its type, and only fall back to inferred type otherwise. gcc/testsuite/ChangeLog: * gfortran.dg/optional_absent_13.f90: New test. --- gcc/fortran/interface.cc | 6 ++- gcc/fortran/trans-expr.cc | 18 ++++--- .../gfortran.dg/optional_absent_13.f90 | 48 +++++++++++++++++++ 3 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/optional_absent_13.f90 diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc index 6258a41cb59..c702239d64d 100644 --- a/gcc/fortran/interface.cc +++ b/gcc/fortran/interface.cc @@ -3382,7 +3382,11 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, return false; } else - a->associated_dummy = get_nonintrinsic_dummy_arg (f); + { + if (a->associated_dummy) + free (a->associated_dummy); + a->associated_dummy = get_nonintrinsic_dummy_arg (f); + } if (a->expr == NULL) { diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 4b90b06fa0a..28c20d89f23 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6931,10 +6931,18 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, { /* Pass a NULL pointer for an absent arg. */ parmse.expr = null_pointer_node; + + /* Is it an absent character dummy? */ + bool absent_char = false; gfc_dummy_arg * const dummy_arg = arg->associated_dummy; - if (dummy_arg - && gfc_dummy_arg_get_typespec (*dummy_arg).type - == BT_CHARACTER) + + /* Fall back to inferred type only if no formal. */ + if (fsym) + absent_char = (fsym->ts.type == BT_CHARACTER); + else if (dummy_arg) + absent_char = (gfc_dummy_arg_get_typespec (*dummy_arg).type + == BT_CHARACTER); + if (absent_char) parmse.string_length = build_int_cst (gfc_charlen_type_node, 0); } @@ -6960,9 +6968,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, || !CLASS_DATA (fsym)->attr.allocatable)); gfc_init_se (&parmse, NULL); parmse.expr = null_pointer_node; - if (arg->associated_dummy - && gfc_dummy_arg_get_typespec (*arg->associated_dummy).type - == BT_CHARACTER) + if (fsym->ts.type == BT_CHARACTER) parmse.string_length = build_int_cst (gfc_charlen_type_node, 0); } else if (fsym && fsym->ts.type == BT_CLASS diff --git a/gcc/testsuite/gfortran.dg/optional_absent_13.f90 b/gcc/testsuite/gfortran.dg/optional_absent_13.f90 new file mode 100644 index 00000000000..9c2039bfb3f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/optional_absent_13.f90 @@ -0,0 +1,48 @@ +! { dg-do run } +! PR fortran/119656 - wrong code with impure elemental subroutine and interface +! +! Derived from testcase at: +! https://fortran-lang.discourse.group/t/ +! problem-with-impure-elemental-subroutine-in-interface-with-gfortran/9545 + +module m2 + implicit none + interface foo + module procedure foo_mat + module procedure foo_df + module procedure foo_cmat + end interface foo +contains + + subroutine foo_mat(x, nacf, label) + real, intent(in) :: x(:,:) + integer, intent(in) :: nacf + character(len=*), intent(in), optional :: label + end subroutine foo_mat + + impure elemental subroutine foo_df(nacf, outu, xstr) + integer , intent(in) :: nacf + integer , intent(in), optional :: outu + character(len=*), intent(in), optional :: xstr + if (present(xstr)) then + if (len (xstr) /= 2) then + print *,"nacf, len(xstr) =", nacf, len(xstr) + stop nacf + end if + end if + end subroutine foo_df + + subroutine foo_cmat(x, nacf, label) + complex, intent(in) :: x(:,:) + integer, intent(in) :: nacf + character(len=*), intent(in), optional :: label + end subroutine foo_cmat + +end module m2 + +program main + use m2, only: foo, foo_df + implicit none + call foo_df(nacf = 1, xstr="ab") + call foo (nacf = 2, xstr="ab") +end program main -- 2.43.0