&& flag_module_private)))
sym->attr.access = ACCESS_PRIVATE;
+ bool in_module_contains = sym->module && sym->ns->proc_name
+ && sym->ns->proc_name->attr.flavor == FL_MODULE;
+
if (!current_function_decl
&& !sym->attr.entry_master && !sym->attr.is_main_program
&& (sym->attr.access != ACCESS_PRIVATE || sym->binding_label
- || sym->attr.public_used))
- TREE_PUBLIC (fndecl) = 1;
+ || sym->attr.public_used || in_module_contains))
+ {
+ TREE_PUBLIC (fndecl) = 1;
+
+ /* Mirror the variable treatment (see gfc_finish_var_decl): PRIVATE
+ module procedures get global linkage but hidden visibility so the
+ symbol is reachable from submodules in the same link without being
+ exported to external DSOs. */
+ if (in_module_contains && sym->attr.access == ACCESS_PRIVATE
+ && !sym->attr.public_used)
+ {
+ DECL_VISIBILITY (fndecl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (fndecl) = true;
+ }
+ }
if (sym->attr.referenced || sym->attr.entry_master)
TREE_USED (fndecl) = 1;
b => export1
end subroutine pub
end module m
-! { dg-final { scan-tree-dump-times "priv" 0 "optimized" } }
+! priv now has TREE_PUBLIC (VISIBILITY_HIDDEN) for submodule host-association,
+! so it is no longer optimized away.
! { dg-final { scan-tree-dump-times "export1 \\(\\)" 1 "optimized" } }
! { dg-final { scan-tree-dump-times "export2 \\(\\)" 1 "optimized" } }
integer, bind(C,name='') :: qq
end module mod
-! The two xfails below have appeared with the introduction of submodules. 'iii' and
+! The xfails below have appeared with the introduction of submodules. 'iii' and
! 'mmm' now are TREE_PUBLIC but has DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN set.
+! Similarly 'two' and 'six' (PRIVATE procedures) now have TREE_PUBLIC +
+! VISIBILITY_HIDDEN so that submodules can reach them via host association.
! { dg-final { scan-assembler "__mod_MOD_aa" } }
! { dg-final { scan-assembler-not "iii" { xfail *-*-* } } }
END MODULE
! { dg-final { scan-assembler "__m_MOD_one" } }
-! { dg-final { scan-assembler-not "two" } }
+! { dg-final { scan-assembler-not "two" { xfail *-*-* } } }
! { dg-final { scan-assembler "three" } }
! { dg-final { scan-assembler-not "four" } }
! { dg-final { scan-assembler "five" } }
-! { dg-final { scan-assembler-not "six" } }
+! { dg-final { scan-assembler-not "six" { xfail *-*-* } } }
! { dg-final { scan-assembler "seven" } }
! { dg-final { scan-assembler "nine" } }
! { dg-final { scan-assembler "__m_MOD_ten" } }
end function get_key
end module m_common_attrs
-! { dg-final { scan-assembler-not "__m_common_attrs_MOD_other" } }
+! { dg-final { scan-assembler-not "__m_common_attrs_MOD_other" { xfail *-*-* } } }
! { dg-final { scan-assembler "__m_common_attrs_MOD_get_key_len" } }
end subroutine bar
end module m
-! { dg-final { scan-assembler-not "__m_MOD_myotherlen" } }
+! { dg-final { scan-assembler-not "__m_MOD_myotherlen" { xfail *-*-* } } }
! { dg-final { scan-assembler "__m_MOD_bar" } }
! { dg-final { scan-assembler "__m_MOD_mylen" } }
--- /dev/null
+! { dg-do run }
+! { dg-additional-sources submodule_private_host_aux.f90 }
+!
+! PR fortran/125430
+!
+! Module-contained procedures with PRIVATE access must retain global ELF
+! linkage so that submodules compiled as separate translation units can
+! reach them via host association.
+
+module m
+ implicit none
+ private
+ public :: pub
+
+ interface
+ module subroutine pub(x)
+ double precision, intent(out) :: x
+ end subroutine
+ end interface
+
+contains
+
+ pure function priv(n) result(x)
+ integer, intent(in) :: n
+ double precision :: x
+ x = dble(n) * 0.5d0
+ end function
+
+end module
--- /dev/null
+! Auxiliary file for submodule_private_host.f90
+! { dg-skip-if "" { *-*-* } }
+submodule(m) ms
+ implicit none
+contains
+ module procedure pub
+ x = priv(6)
+ end procedure
+end submodule
+
+program p
+ use m, only : pub
+ implicit none
+ double precision x
+ call pub(x)
+ if (abs(x - 3.0d0) > 1d-10) stop 1
+end program
contains
- subroutine s1 ! { dg-warning "defined but not used" }
+ subroutine s1
call s2(s3)
contains
subroutine s4 ! { dg-warning "defined but not used" }