On 3/7/26 10:58 AM, Nathaniel Shead wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
OK.
-- >8 -- In r16-6343-gc368ea51b3bae27e3007b9bd89f6162c4c80259f we stopped walking attached decls for a DECL_MODULE_KEYED_DECLS_P entity during dependency gathering so that we didn't unnecessarily expose them if they weren't going to be emitted anyway, and relied on walking the definition to properly setup dependencies. But the linked PR shows that if those attached decls instantiate a template that pushes a hidden friend, they might be found anyway even if we don't find them via the function definition, because we see the hidden decls during add_binding_entity. Apart from causing this crash, walking these hidden decls is both pointless (hidden friends, if needed, will always be walked by their owning class type, and ADL does not need namespace-scope bindings to call them) and expensive, because this can cause a large swathe of other otherwise discarded GMF entities to be marked as reachable. This patch fixes the issue by not creating bindings for hidden friends. Perhaps no hidden entities should have bindings at all, but doing this causes make_dependency to break on the underlying alias decl for a purview DECL_LOCAL_DECL_P when considering additional bindings that need to be created, and I think we might need this to stay around so that we can properly merge these decls anyway (though I haven't investigated this yet). So this patch goes for a more minimal fix for now. PR c++/124390 gcc/cp/ChangeLog: * module.cc (depset::hash::add_binding_entity): Don't create bindings for hidden friends. gcc/testsuite/ChangeLog: * g++.dg/modules/friend-13.C: New test. Signed-off-by: Nathaniel Shead <[email protected]> --- gcc/cp/module.cc | 10 ++++++++++ gcc/testsuite/g++.dg/modules/friend-13.C | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 gcc/testsuite/g++.dg/modules/friend-13.C diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index ccbf124876d..a50de24ccec 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -14918,6 +14918,16 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) than trying to clear out bindings after the fact. */ return false;+ if ((flags & WMB_Hidden)+ && DECL_LANG_SPECIFIC (inner) + && DECL_UNIQUE_FRIEND_P (inner)) + /* Hidden friends will be found via ADL on the class type, + and so do not need to have bindings. Anticipated builtin + functions and the hidden decl underlying a DECL_LOCAL_DECL_P + also don't need exporting, but we should create a binding + anyway so that we can have a common decl to match against. */ + return false; + bool internal_decl = false; if (!header_module_p () && is_tu_local_entity (decl)) { diff --git a/gcc/testsuite/g++.dg/modules/friend-13.C b/gcc/testsuite/g++.dg/modules/friend-13.C new file mode 100644 index 00000000000..8930eca7ded --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/friend-13.C @@ -0,0 +1,17 @@ +// PR c++/124390 +// { dg-additional-options "-fmodules -Wno-global-module -fdump-lang-module" } +// { dg-module-cmi M } + +module; +template <typename T> struct tuple { + template <typename U> friend void f(tuple, U); +}; +template <typename T> tuple<T> make_unique(); +export module M; +void test() { + auto lambda = [] {}; + make_unique<decltype(lambda)>(); +} + +// Hidden friends should be discarded if not used. +// { dg-final { scan-lang-dump-not {Bindings '::f'} module } }
