see the following snippet:
struct config {
int x;
constexpr int multiply() const {
return x*3;
}
};
constexpr config c = {.x = 1};
int main() {
int x = c.multiply();
return x;
}
If I compile this with clang and -O0 I get a function call to multiply even though the object c and the function are marked constexpr. If I compile it with -O1 everything gets optimized as expected. Gcc on the other hand generates no call to multiply.
If I change the main to:
int main() {
constexpr auto y = c.multiply();
int x = y;
return x;
}
If I compile this with clang and -O0 I get not function call and the value 3 directly as stack variable. The -O1 result is the same as above.
So my question is: Does the constexpr evaluation depend on the compiler level? I would expect that in the example 1 the call to multiply would be constexpr and performed compile time. (like gcc does)
BR, go2sh
See https://godbolt.org/z/WvPE5W77h
CodePudding user response:
The Standard just requires that a call to constexpr
is evaluated at compile time if the arguments are constexpr
and the result must be constexpr
due to context. Basically just forcing more restrictions on the author of the function, thus allowing it to be used in constexpr
contexts.
Meaning y
in second snippet forces evaluation at compile time. On the other hand, x
in the first is an ordinary run-time call.
But the as-if rule applies here - as long as the observable effects of the program remain the same, the compiler can generate any instructions it wants. It can evaluate any function, even non-constexpr
ones if it can do so - happens in practice often with constants propagation.
Yes, in general, higher optimization levels will inline more code and push more evaluation to the compile time. But "looking at the assembly" is not an observable effect in the sense above so there are no guarantees. You can use inline
to give a hint for inlining the function instead of calling it (constexpr
is inline by default but for other reasons...) but the compilers can ignore them.
Of course, the compiler can evaluate all constexpr
functions with constexpr
args at compile time, that is why they exist, why clang does not do so with -O0
, I do not know.
If you need guaranteed compile-time evaluation, use consteval
instead.