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.

Reply via email to