While producing a MCVE for this problem I stumbled upon, I've found the following discrepancy between compilers:
Consider the following code :
// constexpr int f(); // 1
constexpr int g() {
constexpr int f(); // 2
return f();
}
constexpr int f() {
return 42;
}
int main() {
constexpr int i = g();
return i;
}
This code compiles on Clang 3.8.0, but fails on GCC 6.1.0 with:
error: 'constexpr int f()' used before its definition
Commenting out // 2
and uncommenting // 1
works on both compilers.
Interestingly, moving f
's definition in place of // 1
compiles, but triggers a warning at // 2
:
warning: inline function 'constexpr int f()' used but never defined
Which compiler is right ?
Although constexpr variables can be given external linkage via the extern keyword, they can not be forward declared, so there is no value in giving them external linkage. This is because the compiler needs to know the value of the constexpr variable (at compile time).
A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.
Actually, extern constexpr does make sense, and would be useful. In particular, static constexpr class member variables automatically have external linkage (which is a huge inconsistency and gotcha - people often forget to add a definition in a . cc file).
Yes ([dcl. constexpr], §7.1. 5/2 in the C++11 standard): "constexpr functions and constexpr constructors are implicitly inline (7.1.
Replacing the constexpr
functions with inline
functions retains the exact same problem (it is okay with the global declaration 1, but not with the function-scope declaration 2.) Since constexpr
implies inline
this seems like the cause.
In this case, with declaration 2, GCC complains:
warning: 'inline' specifier invalid for function 'f' declared out of global scope
and warning: inline function 'int f()' used but never defined
.
It fails to link ("undefined reference to 'f()'
").
So it looks like it gives up on inlining, puts in a call, but doesn't bother emitting code for f()
because all uses are inlined (?), so the link fails.
and Clang complains:
error: inline declaration of 'f' not allowed in block scope
Since constexpr
implies inline
, it seems that this rule that inline declarations are not allowed in block scope should also apply to constexpr
, and so GCC is correct. But the standard does not seem to come out and say this. In the draft I examined, the rule about inline
is in §7.1.2 [dcl.fct.spec], part 3: "The inline specifier shall not appear on a block scope function declaration", but nothing similar appears about constexpr
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With