Title
Zero-initialization and constexpr
Status
cd4
Section
6.9.3 [basic.start]
Submitter
Jason Merrill

Created on 2014-10-20.00:00:00 last changed 87 months ago

Messages

Date: 2015-10-15.00:00:00

[Moved to DR at the October, 2015 meeting.]

Date: 2015-05-15.00:00:00

Proposed resolution (May, 2015):

  1. Rename 6.9.3.2 [basic.start.static] and make the indicated changes, moving parts of its content to a new section immediately following, as indicated below:

  2. 3.6.2 IStatic initialization of non-local variables [basic.start.init.static]

    There are two broad classes of named non-local variables: those with static storage duration (6.7.5.2 [basic.stc.static]) and those with thread storage duration (6.7.5.3 [basic.stc.thread]). Non-local variables Variables with static storage duration are initialized as a consequence of program initiation. Non-local variables Variables with thread storage duration are initialized as a consequence of thread execution. Within each of these phases of initiation, initialization occurs as follows.

    Variables with static storage duration (6.7.5.2 [basic.stc.static]) or thread storage duration (6.7.5.3 [basic.stc.thread]) shall be zero-initialized (9.4 [dcl.init]) before any other initialization takes place. A constant initializer for an object o is an expression that is a constant expression, except that it may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types [Note: such a class may have a non-trivial destructor —end note]. Constant initialization is performed:

    • if each full-expression (including implicit conversions) that appears in the initializer of a reference with static or thread storage duration is a constant expression (7.7 [expr.const]) and the reference is bound to a glvalue designating an object with static storage duration, to a temporary object (see 6.7.7 [class.temporary]) or subobject thereof, or to a function;

    • if an object with static or thread storage duration is initialized by a constructor call, and if the initialization full-expression is a constant initializer for the object;

    • if an object with static or thread storage duration is not initialized by a constructor call and if either the object is value-initialized or every full-expression that appears in its initializer is a constant expression.

    If constant initialization is not performed, a variable with static storage duration (6.7.5.2 [basic.stc.static]) or thread storage duration (6.7.5.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. Static initialization shall be performed before any dynamic initialization takes place. Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, and otherwise is ordered [Note: an explicitly specialized static data member or variable template specialization has ordered initialization. —end note]. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. If a program starts a thread (33.4 [thread.threads]), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization. [Note: This definition permits initialization of a sequence of ordered variables concurrently with another sequence. —end note] [Note: The dynamic initialization of non-local variables is described in 3.6.3 [basic.start.dynamic]; that of local static variables is described in 8.8 [stmt.dcl]. —end note]

    An implementation is permitted to perform the initialization of a non-local variable with static or thread storage duration as a static initialization even if such initialization is not required to be done statically, provided that

    • the dynamic version of the initialization does not change the value of any other object of namespace scope static or thread storage duration prior to its initialization, and

    • the static version of the initialization produces the same value in the initialized variable as would be produced by the dynamic initialization if all variables not required to be initialized statically were initialized dynamically.

    [Note: As a consequence, if the initialization of an object obj1 refers to an object obj2 of namespace scope potentially requiring dynamic initialization and defined later in the same translation unit, it is unspecified whether the value of obj2 used will be the value of the fully initialized obj2 (because obj2 was statically initialized) or will be the value of obj2 merely zero-initialized. For example,

      inline double fd() { return 1.0; }
      extern double d1;
      double d2 = d1;   // unspecified:
                        // may be statically initialized to 0.0 or
                        // dynamically initialized to 0.0 if d1 is
                        // dynamically initialized, or 1.0 otherwise
      double d1 = fd(); // may be initialized statically or dynamically to 1.0
    

    end note]

  3. Insert a new section after 6.9.3.2 [basic.start.static]:

  4. 3.6.3 Dynamic initialization of non-local variables [basic.start.dynamic]
  5. Move part of 6.9.3.2 [basic.start.static] paragraph 2 as paragraph 1 of the new section:

  6. Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, and otherwise is ordered [Note: an explicitly specialized static data member or variable template specialization has ordered initialization. —end note]. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. If a program starts a thread (33.4 [thread.threads]), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization. [Note: This definition permits initialization of a sequence of ordered variables concurrently with another sequence. —end note]
  7. Move paragraphs 4-6 of 6.9.3.2 [basic.start.static] as paragraphs 2-4 of the new section:

  8. It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (6.3 [basic.def.odr]) of any function or variable defined in the same translation unit as the variable to be initialized. [Footnote: A non-local variable with static storage duration having initialization with side-effects must be initialized even if it is not odr-used (6.3 [basic.def.odr], 6.7.5.2 [basic.stc.static]). —end footnote] [Example:

      // - File 1 -
      #include "a.h"
      #include "b.h"
      B b;
      A::A(){
        b.Use();
      }
    
      // - File 2 -
      #include "a.h"
      A a;
    
      // - File 3 -
      #include "a.h"
      #include "b.h"
      extern A a;
      extern B b;
      int main() {
        a.Use();
        b.Use();
    }
    

    It is implementation-defined whether either a or b is initialized before main is entered or whether the initializations are delayed until a is first odr-used in main. In particular, if a is initialized before main is entered, it is not guaranteed that b will be initialized before it is odr-used by the initialization of a, that is, before A::A is called. If, however, a is initialized at some point after the first statement of main, b will be initialized prior to its use in A::A. —end example]

    It is implementation-defined whether the dynamic initialization of a non-local variable with static or thread storage duration is done before the first statement of the initial function of the thread. If the initialization is deferred to some point in time after the first statement of the initial function of the thread, it shall occur before the first odr-use (6.3 [basic.def.odr]) of any variable with thread storage duration defined in the same translation unit as the variable to be initialized.

    If the initialization of a non-local variable with static or thread storage duration exits via an exception, std::terminate is called (14.6.2 [except.terminate]).

  9. Change 8.8 [stmt.dcl] paragraph 4 as follows:
  10. The zero-initialization (9.4 [dcl.init]) of all block-scope variables with static storage duration (6.7.5.2 [basic.stc.static]) or thread storage duration (6.7.5.3 [basic.stc.thread]) is performed before any other initialization takes place. Constant initialization (6.9.3.2 [basic.start.static]) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (6.9.3.2 [basic.start.static]). Otherwise such a variable is initialized Dynamic initialization of a block-scope variable with static storage duration (6.7.5.2 [basic.stc.static]) or thread storage duration (6.7.5.3 [basic.stc.thread]) is performed the first time control passes...

Editing note: all existing cross-references to 6.9.3.2 [basic.start.static] must be examined to determine which of the two current sections should be targeted.

Date: 2014-11-15.00:00:00

Notes from the November, 2014 meeting:

CWG agreed that constant initialization should be considered as happening instead of zero initialization in these cases, making the declarations ill-formed.

Date: 2016-02-15.00:00:00

According to 6.9.3.2 [basic.start.static] paragraph 2,

Variables with static storage duration (6.7.5.2 [basic.stc.static]) or thread storage duration (6.7.5.3 [basic.stc.thread]) shall be zero-initialized (9.4 [dcl.init]) before any other initialization takes place.

Does this apply to constant initialization as well? For example, should the following be well-formed, relying on the presumed zero-initialization preceding the constant initialization?

  constexpr int i = i;
  struct s {
    constexpr s() : v(v) { }
    int v;
  };
  constexpr s s1;
History
Date User Action Args
2017-02-06 00:00:00adminsetstatus: dr -> cd4
2015-11-10 00:00:00adminsetmessages: + msg6064
2015-11-10 00:00:00adminsetstatus: ready -> dr
2015-05-25 00:00:00adminsetmessages: + msg5444
2015-05-25 00:00:00adminsetstatus: drafting -> ready
2014-11-24 00:00:00adminsetmessages: + msg5185
2014-10-20 00:00:00admincreate