https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71125
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Keywords| |diagnostic Status|WAITING |NEW Severity|normal |enhancement --- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Casey Carter from comment #2) > (In reply to Jonathan Wakely from comment #1) > > Is this valid in C++20? > > Definitely not: there are no concept functions in C++20. Right, sorry I was unclear ... I modernised Tom's original code to use C++20 syntax, which still fails to compile, and was asking about that version ... which I didn't actually post and somehow expected everybody to know what I meant. Oops. The code I tested was: template<typename T> constexpr bool C1() { return true; } template<typename T, typename U> concept C1 = true; template<typename T> requires C1<T> void f1() {} // Removing the unused overload avoids the error: template<typename T> constexpr bool C2() { return true; } template<typename T> requires C2<T> // Ok. void f2() {} // Swapping the order of the declarations avoids the error: template<typename T, typename U> concept C3 = true; template<typename T> constexpr bool C3() { return true; } template<typename T> requires C3<T> // Ok. void f3() {} // Swapping the overload that is resolved avoids the error: template<typename T> constexpr bool C4() { return true; } template<typename T, typename U> concept C4 = true; template<typename T> requires C4<T,int> // Ok. void f4() {} // Swapping which overload is declared with the concept specifier avoids the error: template<typename T> concept C5 = true; template<typename T, typename U> constexpr bool C5() { return true; } template<typename T> requires C5<T> // Ok. void f5() {} And the diagnostics from trunk are: 71125.cc:4:18: error: 'template<class T, class U> concept C1' conflicts with a previous declaration 4 | concept C1 = true; | ^ 71125.cc:2:16: note: previous declaration 'constexpr bool C1()' 2 | constexpr bool C1() { return true; } | ^~ 71125.cc:6:12: error: constraint expression does not have type 'bool' 6 | requires C1<T> | ^~~~~ 71125.cc:13:12: error: constraint expression does not have type 'bool' 13 | requires C2<T> // Ok. | ^~~~~ 71125.cc:20:19: error: 'template<class T> constexpr bool C3()' conflicts with a previous declaration 20 | constexpr bool C3() { return true; } | ^ 71125.cc:18:9: note: previous declaration 'template<class T, class U> concept C3' 18 | concept C3 = true; | ^~ 71125.cc:22:12: error: wrong number of template arguments (1, should be 2) 22 | requires C3<T> // Ok. | ^~~~~ 71125.cc:18:9: note: provided for 'template<class T, class U> concept C3' 18 | concept C3 = true; | ^~ 71125.cc:29:18: error: 'template<class T, class U> concept C4' conflicts with a previous declaration 29 | concept C4 = true; | ^ 71125.cc:27:16: note: previous declaration 'constexpr bool C4()' 27 | constexpr bool C4() { return true; } | ^~ 71125.cc:31:12: error: constraint expression does not have type 'bool' 31 | requires C4<T,int> // Ok. | ^~~~~~~~~ 71125.cc:38:19: error: 'template<class T, class U> constexpr bool C5()' conflicts with a previous declaration 38 | constexpr bool C5() { return true; } | ^ 71125.cc:36:9: note: previous declaration 'template<class T> concept C5' 36 | concept C5 = true; | ^~ I think the "conflicts with a previous declaration" diagnostic is reasonable. Maybe "redeclared as a different kind of symbol" would also work. I'll recategorise it as a diagnostic enhancement and confirm it, but I think closing it would also be fine.