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.