https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119034
Bug ID: 119034 Summary: Nested using-declaration doesn't do ADL or uses wrong associated namespace Product: gcc Version: 15.0 Status: UNCONFIRMED Keywords: rejects-valid Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: redi at gcc dot gnu.org Target Milestone: --- namespace foo { struct X { }; void func(X) { } } namespace bar { void func() = delete; template<typename T> concept adl_func = requires(T t) { func(t); }; // #1 template<bool> struct result { template<typename T> using type = decltype(func(T{})); // #2 }; template<> struct result<false> { }; template<typename T> using type = typename result<adl_func<T>>::template type<T>; } template<typename, typename> constexpr bool is_same_v = false; template<typename T> constexpr bool is_same_v<T, T> = true; static_assert( is_same_v<bar::type<foo::X>, void> ); Clang and EDG compile this OK. MSVC rejects it, but I don't understand the error. GCC says: adl.cc: In instantiation of 'struct bar::result<true>': adl.cc:27:11: required by substitution of 'template<class T> using bar::type = typename bar::result<adl_func<T> >::type<T> [with T = foo::X]' 27 | using type = typename result<adl_func<T>>::template type<T>; | ^~~~ adl.cc:33:42: required from here 33 | static_assert( is_same_v<bar::type<foo::X>, void> ); | ^ adl.cc:18:35: error: use of deleted function 'void bar::func()' 18 | using type = decltype(func(T{})); // #2 | ~~~~^~~~~ adl.cc:9:8: note: declared here 9 | void func() = delete; | ^~~~ It seems that the call func(T{}) at #2 does not use namespace foo as an associated namespace, even though T is foo::X, and even though we can't even reach #2 unless the concept at #1 has already confirmed that func(T{}) does use ADL to find foo::func. If the helper classes are written like this then all compilers are happy: template<typename T> struct result { }; template<adl_func T> struct result<T> { using type = decltype(func(T{})); // #2 }; template<typename T> using type = typename result<T>::type; But I was hoping to reduce the number of instantiations by only having result<true> and result<false>, and using an alias template to find the result of the ADL call.