]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: ADL finds all friends (P1787)
authorJason Merrill <jason@redhat.com>
Sat, 1 Nov 2025 18:56:26 +0000 (21:56 +0300)
committerJason Merrill <jason@redhat.com>
Mon, 3 Nov 2025 18:32:26 +0000 (21:32 +0300)
Some libstdc++ tests were failing with import std because ADL didn't find
rethrow_exception, even though it's a friend.  The problem turned out to be
because it's not in the same namespace, and in C++17 ADL only makes hidden
friends visible.  But in C++20 P1787 changed [basic.lookup.argdep]/4.2 to
directly include all friends in the lookup.

Note that my change still excludes class members, even though the standard
doesn't specify that; including implicit object member functions would just
break, and even foreign static/xobj member functions seem like they would be
strange to include.

gcc/cp/ChangeLog:

* name-lookup.cc (name_lookup::adl_class_fns): Include all
namespace-scope friends.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/koenig16.C: New test.

gcc/cp/name-lookup.cc
gcc/testsuite/g++.dg/lookup/koenig16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/adl-11_a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/adl-11_b.C [new file with mode: 0644]

index 2b34102c730b81c4ef3d0b297baed92579da9ee6..ef1360464c5861d0e459fc9e3e4e1265cbab50e3 100644 (file)
@@ -1372,11 +1372,14 @@ name_lookup::adl_class_fns (tree type)
          {
            tree fn = TREE_VALUE (friends);
 
-           /* Only interested in global functions with potentially hidden
-              (i.e. unqualified) declarations.  */
+           /* Before C++20, ADL just makes hidden friends visible, so we
+              only include functions in the same namespace.  After C++20,
+              include all namespace-scope functions.  */
            if (!context)
              context = decl_namespace_context (type);
-           if (CP_DECL_CONTEXT (fn) != context)
+           if (cxx_dialect < cxx20
+               ? CP_DECL_CONTEXT (fn) != context
+               : !DECL_NAMESPACE_SCOPE_P (fn))
              continue;
 
            dedup (true);
diff --git a/gcc/testsuite/g++.dg/lookup/koenig16.C b/gcc/testsuite/g++.dg/lookup/koenig16.C
new file mode 100644 (file)
index 0000000..1d6e4e3
--- /dev/null
@@ -0,0 +1,22 @@
+// Before P1787 (C++20), only hidden friends are included in ADL.
+// After P1787, all friends are included.
+
+namespace N {
+  namespace NN {
+    struct A;
+  }
+  using NN::A;
+  void fn (A);
+  namespace NN {
+    struct A {
+      friend void N::fn (A);
+    };
+  }
+  void fn (A) { }
+}
+
+int main()
+{
+  N::A a;
+  fn(a);                       // { dg-error "not declared" "" { target c++17_down } }
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-11_a.C b/gcc/testsuite/g++.dg/modules/adl-11_a.C
new file mode 100644 (file)
index 0000000..063dd89
--- /dev/null
@@ -0,0 +1,21 @@
+// Before P1787 (C++20), only hidden friends are included in ADL.
+// After P1787, all friends are included.
+
+// { dg-additional-options "-fmodules -Wno-global-module" }
+
+export module M;
+
+namespace N {
+  namespace NN {
+    export struct A;
+  }
+  export using NN::A;
+
+  export void fn (A);
+
+  namespace NN {
+    struct A {
+      friend void N::fn (A);
+    };
+  }
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-11_b.C b/gcc/testsuite/g++.dg/modules/adl-11_b.C
new file mode 100644 (file)
index 0000000..f178915
--- /dev/null
@@ -0,0 +1,12 @@
+// Before P1787 (C++20), only hidden friends are included in ADL.
+// After P1787, all friends are included.
+
+// { dg-additional-options -fmodules }
+
+import M;
+
+int main()
+{
+  N::A a;
+  fn(a);                       // { dg-error "not declared" "" { target c++17_down } }
+}