Reputation:
I've written the following program that compiles with msvc but not with gcc and clang. Demo
template<int x>
struct X {
consteval static int get();
int f() const;
};
//compiles with msvc but not with gcc and clang
template<int x> int X<x>::get(){ return x; }
int main() {
constexpr int i = X<4>::get();
}
As we can see MSVC compiles the above demo while GCC and Clang reject it. GCC says:
error: redeclaration 'static int X<x>::get()' differs in 'consteval' from previous declaration
8 | template<int x> int X<x>::get(){ return x; }
| ^~~~
<source>:4:22: note: previous declaration 'static consteval int X<x>::get()'
4 | consteval static int get();
| ^~~
<source>: In function 'int main()':
<source>:12:30: error: 'static consteval int X<x>::get() [with int x = 4]' used before its definition
12 | constexpr int i = X<4>::get();
| ~~~~~~~~~^~
<source>: At global scope:
<source>:4:22: warning: inline function 'static consteval int X<x>::get() [with int x = 4]' used but never defined
4 | consteval static int get();
| ^~~
I want to know which compiler is correct here according to the C++20 standard.
Upvotes: 5
Views: 167
Reputation: 170153
MSVC is wrong to accept this code silently. This is non-conforming, so it should at least print a diagnostic if it offers an extension (but I suspect it's accepted at all due to a bug).
[dcl.constexpr]
1 If any declaration of a function or function template has a constexpr or consteval specifier, then all its declarations shall contain the same specifier.
IIUC this rule exists due to some ODR-related implications. So GCC/Clang rejecting it outright is more sound.
Upvotes: 8