Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

-- >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 } }
-- 
2.51.0

Reply via email to