Hello All, This is the penultimate submodule fix. It is actually straightforward. However, the version produced by Claude produced error cascades and modified the existing testcase to check for the error. The latter is unacceptable because it hides the result of the original fix in all cases. Instead, I have corrected the error and added the module prefix, where appropriate.
The attached says the rest. It passes regression testing on FC44/x86_64. OK for mainline and eventual backporting to gcc-16? Cheers Paul
From 0de976d38c58e81210b12c2bd46823a55d3e9d39 Mon Sep 17 00:00:00 2001 From: Paul Thomas <[email protected]> Date: Fri, 5 Jun 2026 15:11:20 +0100 Subject: [PATCH] Fortran: require MODULE prefix for separate module procedures [PR121379] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit set_syms_host_assoc clears the 'external' attribute on module procedures when making them accessible via host association in a submodule. The existing check in get_proc_name for a missing MODULE prefix used 'sym->attr.external' as a guard, so the diagnostic was silently suppressed and gfortran accepted — and incorrectly linked — a bare function definition as if it were a valid separate module procedure. Replace 'sym->attr.external' with 'sym->attr.module_procedure', which is not cleared by set_syms_host_assoc, to restore the intended diagnostic. Also update the error message to be clearer about what is required. Both errors have been corrected to avoid returning any value, thereby avoiding an error cascade. After all, these are OK for further processing and argument mismatches etc. can be caught. Additionally, a number of existing testcases contained this error. In order to avoid masking the intended fix, this has been corrected in all cases. 2026-06-05 Paul Thomas <[email protected]> gcc/fortran PR fortran/121379 * decl.cc (get_proc_name): Use module_procedure attr. instead of external to guard the missing-MODULE-prefix diagnostic. Use gfc_error_now and do not return, so that an error cascade does not occur. gcc/testsuite/ChangeLog PR fortran/121379 * gfortran.dg/pdt_59.f03: Add module attribute as required. * gfortran.dg/pr87907.f90: Ditto. * gfortran.dg/pr93461.f90: Ditto. * gfortran.dg/submodule_10.f08: Ditto. * gfortran.dg/submodule_33.f08: Ditto. * gfortran.dg/submodule_36.f90: New test. * gfortran.dg/submodule_37.f90: Add module attribute. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --- gcc/fortran/decl.cc | 26 +++++++++++---- gcc/testsuite/gfortran.dg/pdt_59.f03 | 2 +- gcc/testsuite/gfortran.dg/pr87907.f90 | 2 +- gcc/testsuite/gfortran.dg/pr93461.f90 | 2 +- gcc/testsuite/gfortran.dg/submodule_10.f08 | 14 ++++---- gcc/testsuite/gfortran.dg/submodule_33.f08 | 2 +- gcc/testsuite/gfortran.dg/submodule_36.f90 | 39 ++++++++++++++++++++++ gcc/testsuite/gfortran.dg/submodule_37.f90 | 2 +- 8 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/submodule_36.f90 diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc index fe4aa8119b9..722ce35f20c 100644 --- a/gcc/fortran/decl.cc +++ b/gcc/fortran/decl.cc @@ -1463,7 +1463,7 @@ get_proc_name (const char *name, gfc_symbol **result, bool module_fcn_entry) } } - /* C1246 (R1225) MODULE shall appear only in the function-stmt or + /* F2023: C1247 (R1526) MODULE shall appear only in the function-stmt or subroutine-stmt of a module subprogram or of a nonabstract interface body that is declared in the scoping unit of a module or submodule. */ if (sym->attr.external @@ -1472,12 +1472,24 @@ get_proc_name (const char *name, gfc_symbol **result, bool module_fcn_entry) && !current_attr.module_procedure && sym->attr.proc == PROC_MODULE && gfc_state_stack->state == COMP_CONTAINS) - { - gfc_error_now ("Procedure %qs defined in interface body at %L " - "clashes with internal procedure defined at %C", - name, &sym->declared_at); - return true; - } + gfc_error_now ("Procedure %qs defined in interface body at %L " + "clashes with internal procedure defined at %C", + name, &sym->declared_at); + + /* This is the converse requirement: The separate-module-subprogram for a + module procedure shall have the MODULE prefix or be declared a MODULE + PROCEDURE, otherwise it would be ambiguous. */ + if (sym->attr.module_procedure + && (sym->attr.subroutine || sym->attr.function) + && sym->attr.if_source == IFSRC_IFBODY + && !current_attr.module_procedure + && sym->attr.proc == PROC_MODULE + && gfc_state_stack->state == COMP_CONTAINS + && gfc_state_stack->previous + && gfc_state_stack->previous->state == COMP_SUBMODULE) + gfc_error_now ("Procedure %qs at %C requires the MODULE prefix because " + "it is a module procedure declared in module %qs", + name, sym->module ? sym->module : ""); if (sym && !sym->gfc_new && sym->attr.flavor != FL_UNKNOWN diff --git a/gcc/testsuite/gfortran.dg/pdt_59.f03 b/gcc/testsuite/gfortran.dg/pdt_59.f03 index 7367897c8e7..09ca99ae375 100644 --- a/gcc/testsuite/gfortran.dg/pdt_59.f03 +++ b/gcc/testsuite/gfortran.dg/pdt_59.f03 @@ -30,7 +30,7 @@ end module submodule(input_output_pair_m) input_output_pair_smod contains - function default_real_construct() + module function default_real_construct() type(mini_batch_t) default_real_construct allocate (default_real_construct%input_output_pairs_(2)) default_real_construct%input_output_pairs_%a = [42,43] diff --git a/gcc/testsuite/gfortran.dg/pr87907.f90 b/gcc/testsuite/gfortran.dg/pr87907.f90 index 5c2acaf9b7f..2a99aa7fd6e 100644 --- a/gcc/testsuite/gfortran.dg/pr87907.f90 +++ b/gcc/testsuite/gfortran.dg/pr87907.f90 @@ -12,7 +12,7 @@ end submodule(m) m2 contains - subroutine g(x) ! { dg-error "FUNCTION attribute conflicts with SUBROUTINE" } + module subroutine g(x) ! { dg-error "FUNCTION attribute conflicts with SUBROUTINE" } end end diff --git a/gcc/testsuite/gfortran.dg/pr93461.f90 b/gcc/testsuite/gfortran.dg/pr93461.f90 index 3bef326172f..d6b7b424aec 100644 --- a/gcc/testsuite/gfortran.dg/pr93461.f90 +++ b/gcc/testsuite/gfortran.dg/pr93461.f90 @@ -9,7 +9,7 @@ end module aModuleWithAnAllowedName submodule (aModuleWithAnAllowedName) aSubmoduleWithAVeryVeryVeryLongButEntirelyLegalName contains - subroutine aShortName() + module subroutine aShortName() call aSubroutineWithAVeryLongNameThatWillCauseAProblem() call aSubroutineWithAVeryLongNameThatWillCauseAProblemAlso() end subroutine aShortName diff --git a/gcc/testsuite/gfortran.dg/submodule_10.f08 b/gcc/testsuite/gfortran.dg/submodule_10.f08 index 373b11c9f96..d9968e9b147 100644 --- a/gcc/testsuite/gfortran.dg/submodule_10.f08 +++ b/gcc/testsuite/gfortran.dg/submodule_10.f08 @@ -99,14 +99,14 @@ submodule (error_mod) error_impl_mod use const_mod contains ! checks whether an error has occurred on one of the processes in the execution pool - subroutine errcomm(ictxt, err) + module subroutine errcomm(ictxt, err) integer(mpik_), intent(in) :: ictxt integer(ipk_), intent(inout):: err end subroutine errcomm - subroutine ser_error_handler(err_act) + module subroutine ser_error_handler(err_act) implicit none integer(ipk_), intent(inout) :: err_act @@ -117,7 +117,7 @@ contains return end subroutine ser_error_handler - subroutine par_error_handler(ictxt,err_act) + module subroutine par_error_handler(ictxt,err_act) implicit none integer(mpik_), intent(in) :: ictxt integer(ipk_), intent(in) :: err_act @@ -131,25 +131,25 @@ contains end subroutine par_error_handler - subroutine par_error_print_stack(ictxt) + module subroutine par_error_print_stack(ictxt) integer(mpik_), intent(in) :: ictxt call error(ictxt, abrt=.false.) end subroutine par_error_print_stack - subroutine ser_error_print_stack() + module subroutine ser_error_print_stack() call error() end subroutine ser_error_print_stack - subroutine serror() + module subroutine serror() implicit none end subroutine serror - subroutine perror(ictxt,abrt) + module subroutine perror(ictxt,abrt) use const_mod implicit none integer(mpik_), intent(in) :: ictxt diff --git a/gcc/testsuite/gfortran.dg/submodule_33.f08 b/gcc/testsuite/gfortran.dg/submodule_33.f08 index b61d750def1..85c29183ac1 100644 --- a/gcc/testsuite/gfortran.dg/submodule_33.f08 +++ b/gcc/testsuite/gfortran.dg/submodule_33.f08 @@ -14,7 +14,7 @@ module m end submodule(m) m2 contains - subroutine g(x) ! { dg-error "FUNCTION attribute conflicts with SUBROUTINE" } + module subroutine g(x) ! { dg-error "FUNCTION attribute conflicts with SUBROUTINE" } integer, intent(in) :: x ! { dg-error "Unexpected data declaration" } end end diff --git a/gcc/testsuite/gfortran.dg/submodule_36.f90 b/gcc/testsuite/gfortran.dg/submodule_36.f90 new file mode 100644 index 00000000000..a2b03f84f7f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/submodule_36.f90 @@ -0,0 +1,39 @@ +! { dg-do compile } +! +! Test the fix for pr121379, in which the missing MODULE prefix for 'realg' was +! not detected. +! +! Contributed by Paul Thomas <[email protected]> +! +module m + interface g + real module function realg1 (arg1, arg2) + real, intent(in) :: arg1, arg2 + end + end interface + + interface h + real module function realg2 (arg1, arg2) + real, intent(in) :: arg1, arg2 + end + end interface + +contains +end module m + +submodule (m) subm +contains + real module function realg1 (arg1, arg2) + real, intent(in) :: arg1, arg2 + realg1 = arg1 + arg2 + end + + real function realg2 (arg1, arg2) ! { dg-error "requires the MODULE prefix" } + real, intent(in) :: arg1, arg2 + realg2 = arg1 + arg2 + end +end + + use m + print *, g(1.0, 1.0), h(2.0, 2.0) +end diff --git a/gcc/testsuite/gfortran.dg/submodule_37.f90 b/gcc/testsuite/gfortran.dg/submodule_37.f90 index 2e8c01c9453..3bfde9ab67b 100644 --- a/gcc/testsuite/gfortran.dg/submodule_37.f90 +++ b/gcc/testsuite/gfortran.dg/submodule_37.f90 @@ -37,7 +37,7 @@ end module t submodule (t) ts contains - function bp(s) + module function bp(s) class(b), intent(inout) :: s class(c), pointer :: bp select type (s) -- 2.54.0
