From 8f6c9ebc7d7726596c94f164176b914801c5665c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 1 Nov 2025 21:56:26 +0300 Subject: [PATCH] c++: ADL finds all friends (P1787) 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 | 9 ++++++--- gcc/testsuite/g++.dg/lookup/koenig16.C | 22 ++++++++++++++++++++++ gcc/testsuite/g++.dg/modules/adl-11_a.C | 21 +++++++++++++++++++++ gcc/testsuite/g++.dg/modules/adl-11_b.C | 12 ++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/koenig16.C create mode 100644 gcc/testsuite/g++.dg/modules/adl-11_a.C create mode 100644 gcc/testsuite/g++.dg/modules/adl-11_b.C diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 2b34102c730..ef1360464c5 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -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 index 00000000000..1d6e4e367eb --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/koenig16.C @@ -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 index 00000000000..063dd89983a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/adl-11_a.C @@ -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 index 00000000000..f1789151834 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/adl-11_b.C @@ -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 } } +} -- 2.47.3