The following program compiles successfully with all major compilers:
struct S {
constexpr S(const S&){};
constexpr S() = default;
};
int main(void) {
S s1{};
constexpr S s2{ s1 };
}
The rule governing the initialization of constexpr variables is [dcl.constexpr]/10: (emphasis mine)
A
constexprspecifier used in an object declaration declares the object as const. Such an object shall have a literal type and shall be initialized. In anyconstexprvariable declaration, the full-expression of the initialization shall be a constant expression (7.7). Aconstexprvariable shall have constant destruction.
Per the bold part, the full-expression of the initialization shall be a constant expression. Per my understanding, the full-expression here is the init-declarator per [into.execution]/5:
A full-expression is
- [..] (5.4) an init-declarator ([dcl.decl]) [..]
Per the grammar of init-declarator, the init-declarator is a declarator followed by an initializer:
init-declarator:
declarator initializer
Given this information, we can conclude that the full-expression of the initialization constexpr S s2{ s1 }; is s2{ s1 } where s2 is a declarator and { s1 } is an initializer.
Now, [dcl.constexpr]/10 tells us that the full-expression (which is s2{ s1 } init-declarator) shall be a constant expression. And I've stucked at this point. Per [expr.const]/11, a constant expression is either a glvalue or prvalue core constant expression (with some additional constraints).
For the above example, I found myself reading [dcl.constexpr]/10 as: "the full-expression s2{ s1 } shall be a glvalue or prvalue core constant expression". So how the init-declarator s2{ s1 } can be a glvalue or prvalue core constant expression? As you can see, my interpretation led me to a wrong theory. So, What did I misread/conflate here?
Intuitively, I just see the init-declarator s2{ s1 } is a copy constructor call with s1 as an argument. But that is not the problem I'm trying to understand. Also, why the above program is well-formed is not what I'm trying to ask for. Instead, I need to know why my interpretation of this rule has not brought us to a reasonable conclusion.
EDIT
Note, the same problem we will encounter with this simple example (Demo):
int main(void) {
static const int i = 42;
constexpr int j = i;
constexpr const int &r = i;
}
The full-expression of the initialization constexpr int j = i; is the init-declarator j = i, where j is a declarator and = i is an initializer So, How can the full-expression j = i be a prvalue core constant expression?
The full-expression of the initialization constexpr const int &r = i; is the init-declarator &r = i, where &r is a declarator and = i is an initializer. So, How can the full-expression &r = i be a glvalue core constant expression?