Created on 2022-02-21.00:00:00 last changed 23 months ago
Additional notes (January, 2023)
The standard does not guarantee stable results when reading padding bits, i.e. bits that are not part of the value representation of some in-lifetime object. In C, explicit rules keep padding bits stable; they are allowed to change only if a store to any class member occurs.
CWG 2022-12-02
The resolution shown above would leave padding bits uninitialized. In contrast, zero-initialization does set padding bits to 0 to possibly facilitate memcmp. Additional example:
struct C { int a; int b; C() : b(a) {} // #1 }; constinit C x; // OK when zero-initializing first, because #1 reads zero-initialized a?
2022-12-03
Forwarded to EWG with cplusplus/papers#1380.
Notes from the November, 2022 meeting
CWG preferred to zero-initialize a.y in the example, and keep #1 well-formed.
Possible resolution:
Change in 6.9.3.2 [basic.start.static] paragraph 2 as follows:
Constant initialization is performed if a variable or temporary object with static or thread storage duration is constant-initialized (7.7 [expr.const]).If constant initialization is not performed, aA variable with static storage duration (6.7.6.2 [basic.stc.static]) or thread storage duration (6.7.6.3 [basic.stc.thread]) or a subobject thereof is zero-initialized (9.4 [dcl.init]) if constant initialization is not performed or if it does not initialize that subobject. Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. All static initialization strongly happens before (6.9.2.2 [intro.races]) any dynamic initialization.
Alternative suggested resolution (March, 2022) [SUPERSEDED]:
Change in 7.7 [expr.const] paragraph 11 as follows:
A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:
- if the value is an object of class type, each non-static data member of reference type refers to an entity that is a permitted result of a constant expression,
- if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object (7.6.6 [expr.add]), the address of a non-immediate function, or a null pointer value,
- if the value is of pointer-to-member-function type, it does not designate an immediate function, and
- if the value is an object of class or array type, each subobject is initialized (11.9.3 [class.base.init]) and satisfies these constraints for the value.
Suggested resolution [SUPERSEDED]:
Change in 7.7 [expr.const] paragraph 2:A variable or temporary object o is constant-initialized if
- either it has an initializer or its default-initialization results in some initialization being performed, and
- every non-variant non-static data member and base class subobject is initialized (11.9.3 [class.base.init]), and
- the full-expression of its initialization is a constant expression when interpreted as a constant-expression, except that if o is an object, that full-expression may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types.
Consider:
struct A { int x = 1; int y; };
constinit A a; // static storage duration; #1
The treatment of this example changed with P1331R2 (Permitting trivial default initialization in constexpr contexts), adopted 2019-07. Prior to this paper, the default constructor of A was not constexpr because it left a data member uninitialized. With paper P1331, the restriction was shifted to reading uninitialized objects during constant evaluation, and the variable a now satisfies the requirements for "constant-initialized" in 7.7 [expr.const] paragraph 2:
A variable or temporary object o is constant-initialized if
- either it has an initializer or its default-initialization results in some initialization being performed, and
- the full-expression of its initialization is a constant expression when interpreted as a constant-expression, except that if o is an object, that full-expression may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types.
Zero-initialization is not performed prior to constant-initialization per 6.9.3.2 [basic.start.static] paragraph 2:
Constant initialization is performed if a variable or temporary object with static or thread storage duration is constant-initialized (7.7 [expr.const]). If constant initialization is not performed, a variable with static storage duration (6.7.6.2 [basic.stc.static]) or thread storage duration (6.7.6.3 [basic.stc.thread]) is zero-initialized (9.4 [dcl.init]). Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization.
Thus, #1 is valid and a is statically initialized, but a.y would remain uninitialized, which is surprising for an object with static storage duration.
Current implementations diagnose an error at #1, because the variable a is actually not considered to be constant-initialized.
This issue is closely related to issue 2558.
History | |||
---|---|---|---|
Date | User | Action | Args |
2023-01-20 22:53:26 | admin | set | messages: + msg7147 |
2022-12-03 19:19:31 | admin | set | messages: + msg7076 |
2022-12-03 14:05:33 | admin | set | status: drafting -> open |
2022-12-01 21:11:16 | admin | set | messages: + msg7071 |
2022-11-20 07:54:16 | admin | set | status: open -> drafting |
2022-02-21 00:00:00 | admin | create | |
2022-02-18 07:47:23 | admin | set | messages: + msg6740 |
2022-02-18 07:47:23 | admin | set | messages: + msg6739 |