It seems that the rules for the compile-time keywords: constexpr
, consteval
and constinit
are defined well enough for compilers to warn if you misapply the label.
It would make sense that (much like inline) the compiler can, in all places, apply rules to determine if, in fact, code could have one of the compile-time keywords applied and, be forced, per language specification, to compile as much as possible as if the compile-time keywords had been applied.
Or, at a minimum, if a compile-time keyword is applied to a function and the code would have qualified with had the correct compile-time keywords been applied. Compile that function, as if all the functions called had the correct compile-time keywords.
Here is a simple example:
#include <tuple>
consteval std::tuple<int, int> init1(int x, int y)
{
return {x,y};
}
std::tuple<int, int>& foo1()
{
static constinit std::tuple<int, int> x=init1(1,2);
return x;
}
std::tuple<int, int> init2(int x, int y)
{
return {x,y};
}
std::tuple<int, int>& foo2()
{
static std::tuple<int, int> x=init2(1,2);
return x;
}
static std::tuple<int, int> x3=init2(1,2);
std::tuple<int, int>& foo3()
{
return x3;
}
see it here: https://godbolt.org/z/KrzGfnEo7
Note that init1/foo1 are fully specified with compile-time keywords and there is no need for a guard variable, since it is initialized completely (not just 0 filled).
The question is about why the compiler doesn't do the same in the cases of init2/foo2 or x3/foo3? Or more precisely why the compiler is allowed NOT to initialize fully at compile time.
EDIT (as per comment) see (Why do we need to mark functions as constexpr?) constexpr
would be required. I am concerned more with cases of consteval
and constinit
. Could the specification be modified to require trying to resolve code at compile-time and not failing because of the absence of constexpr
? This would allow interface contracts to just use constexpr
as per the related question.