https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101460
Bug ID: 101460
Summary: Useless cascade of overload resolution errors for
invalid expression
Product: gcc
Version: 12.0
Status: UNCONFIRMED
Keywords: diagnostic
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: redi at gcc dot gnu.org
Target Milestone: ---
template<bool> struct enable_if { };
template<> struct enable_if<true> { using type = void; };
template<bool B>
using enable_if_t = typename enable_if<B>::type;
struct tuple { };
struct pair { };
template<unsigned N> enable_if_t<N == 1> get(tuple&) { }
template<unsigned N> enable_if_t<N == 1> get(const tuple&) { }
template<unsigned N> enable_if_t<N == 1> get(pair&) { }
template<unsigned N> enable_if_t<N == 1> get(const pair&) { }
template<int N>
constexpr unsigned
frob()
{
static_assert(N == 1, "user-friendly diagnostic");
return unsigned{N}; // narrowing check, reject negative values
}
template<int N> void get_n(tuple& t) { get<frob<N>()>(t); }
int main()
{
tuple t;
get_n<-1>(t);
}
This prints a wall of errors:
stupid.C: In instantiation of 'constexpr unsigned int frob() [with int N =
-1]':
stupid.C:23:51: required from 'void get_n(tuple&) [with int N = -1]'
stupid.C:28:12: required from here
stupid.C:19:19: error: static assertion failed: user-friendly diagnostic
19 | static_assert(N == 1, "user-friendly diagnostic");
| ~~^~~~
stupid.C:19:19: note: '(-1 == 1)' evaluates to false
stupid.C:20:20: error: narrowing conversion of '-1' from 'int' to 'unsigned
int' [-Wnarrowing]
20 | return unsigned{N}; // narrowing check, reject negative values
| ^
stupid.C:21:1: error: body of 'constexpr' function 'constexpr unsigned int
frob() [with int N = -1]' not a return-statement
21 | }
| ^
stupid.C: In instantiation of 'void get_n(tuple&) [with int N = -1]':
stupid.C:28:12: required from here
stupid.C:23:54: error: no matching function for call to
'get<frob<-1>()>(tuple&)'
23 | template<int N> void get_n(tuple& t) { get<frob<N>()>(t); }
| ~~~~~~~~~~~~~~^~~
stupid.C:10:42: note: candidate: 'template<unsigned int N> enable_if_t<(N ==
1)> get(tuple&)'
10 | template<unsigned N> enable_if_t<N == 1> get(tuple&) { }
| ^~~
stupid.C:10:42: note: template argument deduction/substitution failed:
stupid.C:23:51: error: 'constexpr unsigned int frob() [with int N = -1]' called
in a constant expression
23 | template<int N> void get_n(tuple& t) { get<frob<N>()>(t); }
| ~~~~~~~^~
stupid.C:17:1: note: 'constexpr unsigned int frob() [with int N = -1]' is not
usable as a 'constexpr' function because:
17 | frob()
| ^~~~
stupid.C:23:51: note: in template argument for type 'unsigned int'
23 | template<int N> void get_n(tuple& t) { get<frob<N>()>(t); }
| ~~~~~~~^~
stupid.C:11:42: note: candidate: 'template<unsigned int N> enable_if_t<(N ==
1)> get(const tuple&)'
11 | template<unsigned N> enable_if_t<N == 1> get(const tuple&) { }
| ^~~
stupid.C:11:42: note: template argument deduction/substitution failed:
stupid.C:23:51: error: 'constexpr unsigned int frob() [with int N = -1]' called
in a constant expression
23 | template<int N> void get_n(tuple& t) { get<frob<N>()>(t); }
| ~~~~~~~^~
stupid.C:23:51: note: in template argument for type 'unsigned int'
stupid.C:12:42: note: candidate: 'template<unsigned int N> enable_if_t<(N ==
1)> get(pair&)'
12 | template<unsigned N> enable_if_t<N == 1> get(pair&) { }
| ^~~
stupid.C:12:42: note: template argument deduction/substitution failed:
stupid.C:23:51: error: 'constexpr unsigned int frob() [with int N = -1]' called
in a constant expression
23 | template<int N> void get_n(tuple& t) { get<frob<N>()>(t); }
| ~~~~~~~^~
stupid.C:23:51: note: in template argument for type 'unsigned int'
stupid.C:13:42: note: candidate: 'template<unsigned int N> enable_if_t<(N ==
1)> get(const pair&)'
13 | template<unsigned N> enable_if_t<N == 1> get(const pair&) { }
| ^~~
stupid.C:13:42: note: substitution of deduced template arguments resulted in
errors seen above
This is reduced from libstdc++ where there are more overloads of get<N> and all
of them get tried, and all of them print exactly the same error.
Why are we even attempting overload resolution when the expression is invalid?
Is the invalid non-constant frob<-1>() call going to suddenly become valid if
we keep trying hard enough?
If PR 96286 gets fixed then the static_assert in frob should stop compilation,
but if we remove that from the code above then we'll still get a wall of
unhelpful errors. Constant evaluation of frob<-1>() failed, so stop trying to
use it as a template argument.