https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90971

--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> ---
#include <type_traits>

template<typename T> struct is_foo : std::false_type { };
template<typename T> constexpr bool is_foo_v = is_foo<T>::value;

template<typename T, typename = typename
std::enable_if<is_foo<T>::value>::type>
void bar1(T) { }

template<typename T, typename = std::enable_if_t<is_foo<T>::value>>
void bar2(T) { }

template<typename T, typename = std::enable_if_t<is_foo_v<T>>>
void bar3(T) { }

int main()
{
  bar1(1);
  bar2(1);
  bar3(1);
}

GCC prints:

enab.cc: In function 'int main()':
enab.cc:17:9: error: no matching function for call to 'bar1(int)'
   17 |   bar1(1);
      |         ^
enab.cc:7:6: note: candidate: 'template<class T, class> void bar1(T)'
    7 | void bar1(T) { }
      |      ^~~~
enab.cc:7:6: note:   template argument deduction/substitution failed:
enab.cc:6:22: error: no type named 'type' in 'struct std::enable_if<false,
void>'
    6 | template<typename T, typename = typename
std::enable_if<is_foo<T>::value>::type>
      |                      ^~~~~~~~
enab.cc:18:9: error: no matching function for call to 'bar2(int)'
   18 |   bar2(1);
      |         ^
enab.cc:10:6: note: candidate: 'template<class T, class> void bar2(T)'
   10 | void bar2(T) { }
      |      ^~~~
enab.cc:10:6: note:   template argument deduction/substitution failed:
In file included from enab.cc:1:
/home/jwakely/gcc/10/include/c++/10.0.0/type_traits: In substitution of
'template<bool _Cond, class _Tp> using enable_if_t = typename
std::enable_if::type [with bool _Cond = std::integral_constant<bool,
false>::value; _Tp = void]':
enab.cc:9:22:   required from here
/home/jwakely/gcc/10/include/c++/10.0.0/type_traits:2553:11: error: no type
named 'type' in 'struct std::enable_if<false, void>'
 2553 |     using enable_if_t = typename enable_if<_Cond, _Tp>::type;
      |           ^~~~~~~~~~~
enab.cc:19:9: error: no matching function for call to 'bar3(int)'
   19 |   bar3(1);
      |         ^
enab.cc:13:6: note: candidate: 'template<class T, class> void bar3(T)'
   13 | void bar3(T) { }
      |      ^~~~
enab.cc:13:6: note:   template argument deduction/substitution failed:



It would be better if the first and second errors both showed the location as
the default template argument in the function template's template-head.
Currently the first one shows the 'typename' before it:

enab.cc:7:6: note:   template argument deduction/substitution failed:
enab.cc:6:22: error: no type named 'type' in 'struct std::enable_if<false,
void>'
    6 | template<typename T, typename = typename
std::enable_if<is_foo<T>::value>::type>
      |                      ^~~~~~~~


And the second one shows the failure as being inside the enable_if_t alias:

enab.cc:10:6: note:   template argument deduction/substitution failed:
In file included from enab.cc:1:
/home/jwakely/gcc/10/include/c++/10.0.0/type_traits: In substitution of
'template<bool _Cond, class _Tp> using enable_if_t = typename
std::enable_if::type [with bool _Cond = std::integral_constant<bool,
false>::value; _Tp = void]':
enab.cc:9:22:   required from here
/home/jwakely/gcc/10/include/c++/10.0.0/type_traits:2553:11: error: no type
named 'type' in 'struct std::enable_if<false, void>'
 2553 |     using enable_if_t = typename enable_if<_Cond, _Tp>::type;
      |           ^~~~~~~~~~~

I think I'd prefer if both of these were special cased for std::enable_if and
std::enable_if_t and showed the location as the argument to it:

enab.cc:7:6: note:   template argument deduction/substitution failed:
enab.cc:6:22: error: enable_if condition not satisfied 'is_foo<T>::value'
    6 | template<typename T, typename = typename
std::enable_if<is_foo<T>::value>::type>
      |                                                        
^~~~~~~~~~~~~~~~


The third error is especially bad, as no reason is given at all:

enab.cc:13:6: note:   template argument deduction/substitution failed:




Clang prints almost the same thing for all three cases:

enab.cc:17:3: error: no matching function for call to 'bar1'
  bar1(1);
  ^~~~
enab.cc:7:6: note: candidate template ignored: requirement 'is_foo<int>::value'
was not satisfied [with T = int]
void bar1(T) { }
     ^
enab.cc:18:3: error: no matching function for call to 'bar2'
  bar2(1);
  ^~~~
enab.cc:10:6: note: candidate template ignored: requirement
'is_foo<int>::value' was not satisfied [with T = int]
void bar2(T) { }
     ^
enab.cc:19:3: error: no matching function for call to 'bar3'
  bar3(1);
  ^~~~
enab.cc:13:6: note: candidate template ignored: requirement 'is_foo_v<int>' was
not satisfied [with T = int]
void bar3(T) { }
     ^
3 errors generated.

Reply via email to