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.