N2993 = 09-0183
Jens Maurer <Jens.Maurer@gmx.net>
2009-10-21

Expanding the meaning of variable

This paper presents working paper changes to address the following core issues: It also addresses N2800 comment UK 26 and N2800 comment UK 22.

The goal of these changes is to expand the meaning of "variable" to encompass both named objects and references, and to apply the term consistently wherever feasible. While doing so, the following miscellaneous issues found during review were also addressed

Proposed changes

No change in 1.3.10 defns.parameter.

Change 1.10 intro.multithread paragraph 5 as follows:

... [ Note: ... In general this will be impossible since different threads may observe modifications to different variables objects in inconsistent orders. -- end note ]
Change 1.10 intro.multithread paragraph 7 as follows:
... [ Note: ... For atomic variables objects, the definition is clear. ... -- end note ]
Change 1.10 intro.multithread paragraph 12 as follows:
... [ Note: This states that operations on ordinary variables objects are not visibly reordered. ... -- end note ]
Change 2.1 lex.phases paragraph 1, number 9 as follows:
9. All external object and function entity references are resolved. Library components are linked to satisfy external references to functions and objects entities not defined in the current translation...
Change 3 basic paragraph 3:
An entity is a value, object, variable, reference, function, enumerator, type, class member, template, template specialization, namespace, parameter pack, concept, or concept map.
Change 3 basic paragraph 6:
A variable is introduced by the declaration of a reference other than a non-static data member or of an object. The variable's name denotes the object or reference.
No change in 3.2 basic.def.odr paragraph 1.

Change 3.2 basic.def.odr paragraph 2 as follows:

... An object A variable or non-overloaded function whose name appears as a potentially-evaluated expression is used unless it is an object that satisfies the requirements for appearing in a constant expression...
Change 3.2 basic.def.odr paragraph 3 as follows:
Every program shall contain exactly one definition of every non-inline function or object variable that is used in that program...
Change 3.3 basic.scope paragraph 4, bullet 2 as follows:
Change 3.3.1 basic.scope.pdecl paragraph 9 as follows:
Function declarations at block scope and object variable declarations with the extern specifier at block scope refer to declarations that are members of an enclosing namespace...
Change 3.3.11 basic.scope.hiding paragraph 2 as follows:
A class name (9.1 class.name) or enumeration name (7.2 dcl.enum) can be hidden by the name of an object a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and an object a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the object variable, data member, function, or enumerator name is visible.
Change 3.4.1 basic.lookup.unqual paragraph 14 as follows:
If a variable member of a namespace is defined outside of the scope of its namespace then any name used that appears in the definition of the variable member (after the declarator-id) is looked up as if the definition of the variable member occurred in its namespace. ...
Change 3.4.3 basic.lookup.qual paragraph 1 as follows:
...During the lookup for a name preceding the :: scope resolution operator, object variable, function, and enumerator names are ignored...
Change 3.4.3.2 namespace.qual paragraph 5 as follows:
During the lookup of a qualified namespace member name, if the lookup finds more than one declaration of the member, and if one declaration introduces a class name or enumeration name and the other declarations either introduce the same object variable, the same enumerator or a set of functions, the non-type name hides the class or enumeration name if and only if the declarations are from the same namespace; otherwise (the declarations are from different namespaces), the program is ill-formed. ...
No change in 3.5 basic.link paragraph 2.

Change 3.5 basic.link paragraph 3 as follows:

A name having namespace scope (3.3.6 basic.scope.namespace) has internal linkage if it is the name of
Change 3.5 basic.link paragraph 4 as follows:
A name having namespace scope has external linkage if it is the name of
Change 3.5 basic.link paragraph 6 as follows:
The name of a function declared in block scope and the name of an object a variable declared by a block scope extern declaration have linkage. ...
Change 3.5 basic.link paragraph 8 as follows:
... A type without linkage shall not be used as the type of a variable or function with linkage, unless the variable or function that entity has extern "C" linkage (7.5), or ...
Change 3.5 basic.link paragraph 9 as follows:
Two names that are the same (clause 3) and that are declared in different scopes shall denote the same object, reference variable, function, type, enumerator, template or namespace if ...
Change 3.5 basic.link paragraph 10 as follows:
...the types specified by all declarations referring to a given object variable or function shall be identical...
Change the section heading of 3.6.2 basic.start.init as follows:
3.6.2 Initialization of non-local objects variables
Change 3.6.2 basic.start.init paragraph 1 as follows:
There are two broad classes of named non-local objects variables: those with static storage duration (3.7.1 basic.stc.static) and those with thread storage duration (3.7.2 basic.stc.thread). Non-local objects variables with static storage duration are initialized as a consequence of program initiation. Non-local objects variables with thread storage duration are initialized as a consequence of thread execution. ...
Change 3.6.2 basic.start.init paragraph 2 as follows:
Objects Variables with static storage duration (3.7.1 basic.stc.static) or thread storage duration (3.7.2 basic.stc.thread) shall be zero-initialized (8.5 dcl.init) before any other initialization takes place.

... Dynamic initialization of a non-local object variable with static storage duration is either ordered or unordered. Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization. Other objects defined in namespace scope non-local variables with static storage duration have ordered initialization. Objects 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 (30.2 thread.threads), the subsequent initialization of an object a variable is unsequenced with respect to the initialization of an object a variable defined in a different translation unit. Otherwise, the initialization of an object a variable is indeterminately sequenced with respect to the initialization of an object a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of an object a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of an object a variable is indeterminately sequenced with respect to every other dynamic initialization. [ Note: This definition permits initialization of a sequence of ordered objects variables concurrently with another sequence. -- end note ] [ Note: 8.5.1 dcl.init.aggr describes the order in which aggregate members are initialized. The initialization of local static objects variables is described in 6.7 stmt.dcl. -- end note ]

Change 3.6.2 basic.start.init paragraph 3 as follows:
An implementation is permitted to perform the initialization of an object of namespace scope a non-local variable with static storage duration as a static initialization even if such initialization is not required to be done statically, provided that
Change 3.6.2 basic.start.init paragraph 4 as follows:
It is implementation-defined whether the dynamic initialization (8.5 dcl.init, 9.4 class.static, 12.1 class.ctor, 12.6.1 class.expl.init) of an object of namespace scope 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 use of any function or object variable defined in the same translation unit as the object variable to be initialized. [ Footnote: An object defined in namespace scope A non-local variable with static storage duration having initialization with side-effects must be initialized even if it is not used (3.7.1 basic.stc.static). ] ...
Change 3.6.2 basic.start.init paragraph 5 as follows:
It is implementation-defined whether the dynamic initialization (8.5 dcl.init, 9.4 class.static, 12.1 class.ctor, 12.6.1 class.expl.init) of an object of namespace scope a non-local variable with static or thread storage duration and with 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 use of any object variable with thread storage duration defined in the same translation unit as the object variable to be initialized.
Change 3.6.2 basic.start.init paragraph 6 as follows:
If construction or destruction of a non-local static or thread duration object ends in throwing an uncaught exception, the result is to call std::terminate (18.7.3.3 terminate) [ Note: If the initialization of a non-local variable with static or thread storage duration terminates by throwing an exception, std::terminate is called (see 15.5.1 except.terminate). ]
Drafting note: This change (together with the corresponding change in 15.5.1) addresses const A& a = ( B(), A() ) ; assume B() throws an exception: the B() temporary is not lifetime-extended, so it's not the "construction of a non-local static duration object", so the wording falls into a black hole. The next change addresses the "destruction" case.

Add at the end of 3.6.3 basic.start.term paragraph 1:

... [ Note: If the destruction of a non-local object with static or thread storage duration terminates by throwing an exception, std::terminate is called (see 15.5.1 except.terminate). ]
No change in the rest of 3.6.3: references don't have destructors and temporaries would be lifetime-extended so that "object with static/thread storage duration" fits them.

Change 3.7.1 basic.stc.static paragraphs 1 and 2 as follows:

All objects variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these objects entities shall last for the duration of the program (3.6.2 basic.start.init, 3.6.3 basic.start.term).

If an object of a variable with static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy may be eliminated as specified in 12.8 class.copy.

No change in 3.7.1 basic.stc.static paragraph 3.

Change 3.7.2 basic.stc.thread paragraphs 1 and 2 as follows:

All objects and references variables declared with the thread_local keyword have thread storage duration. The storage for these objects and references entities shall last for the duration of the thread in which they are created. There is a distinct object or reference per thread, and use of the declared name refers to the object or reference entitiy associated with the current thread.

An object or reference A variable with thread storage duration shall be initialized before its first use and, if constructed, shall be destroyed on thread exit.

Change 3.7.3 basic.stc.auto paragraphs 1, 2, and 3 as follows:
Local objects variables explicitly declared register or not explicitly declared static or extern have automatic storage duration. The storage for these objects entities lasts until the block in which they are created exits.

[ Note: these objects variables are initialized and destroyed as described in 6.7. -- end note ]

If a named automatic object variable with automatic storage duration has initialization or a destructor with side effects, it shall not be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to be unused, except that a class object or its copy may be eliminated as specified in 12.8 class.copy.

Change 3.9.1 basic.fundamental paragraph 6 as follows:
Values of type bool are either true or false. [ Footnote: Using a bool value in ways described by this International Standard as "undefined," such as by examining the value of an uninitialized automatic variable object, might cause it to behave as if it is neither true nor false. ] ...
Change 5.1 expr.prim paragraph 4 as follows:
... [ Note: the use of :: allows a type, an object, a function, an enumerator, or a namespace an entity declared in the global namespace to be referred to even if its identifier name has been hidden (3.4.3 basic.lookup.qual). -- end note ]
Drafting note: This is an en passant fix.

No change in 5.1 expr.prim paragraph 7.

No change in 5.1 expr.prim paragraph 8.

Change 5.1.2 expr.prim.lambda paragraph 9 as follows:

A lambda-expression's compound-statement can use (see above) this from an immediately-enclosing member function definition, as well as variables and references with automatic storage duration from an immediately-enclosing function definition or lambda-expression, provided these entities are captured (as described below). Any other use (3.2 basic.def.odr) of a variable or reference with automatic storage duration declared outside the lambda-expression is ill-formed. [ Example: ...
Change 5.1.2 expr.prim.lambda paragraph 10 as follows:
The identifiers in a capture-list are looked up using the usual rules for unqualified name lookup (3.4.1 basic.lookup.unqual); each such lookup shall find a variable or reference with automatic storage duration. An entity (i.e. a variable, a reference, or this) is said to be explicitly captured if it appears in the lambda-expression's capture-list. An explicitly captured entity is used (3.2 basic.def.odr).
Change 5.1.2 expr.prim.lambda paragraph 11 as follows:
If a lambda-expression has an associated capture-default and its compound-statement uses (3.2 basic.def.odr) this or a variable or reference with automatic storage duration declared in an enclosing function or lambda-expression and the used entity is not explicitly captured, then the used entity is said to be implicitly captured. ...
Change 5.2.9 expr.static.cast paragraph 5 as follows:
... [ Note: however, if the value is in a temporary variable object (12.2 class.temporary), the destructor for that variable object is not executed until the usual time, and the value of the variable object is preserved for the purpose of executing the destructor. -- end note ] ...
Change 5.19 expr.const paragraph 2 bullet 4 sub-bullet 1 as follows:
Change 6.5.1 stmt.while paragraph 2 as follows:
The object variable created in a condition is destroyed and created with each iteration of the loop...
Change 6.6 stmt.jump paragraph 2 as follows:
On exit from a scope (however accomplished), variables objects with automatic storage duration (3.7.3) that have been constructed in that scope are destroyed in the reverse order of their construction. ... Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of variables objects with automatic storage duration that are in scope at the point transferred from but not at the point transferred to. ...
No change in 6.7 stmt.dcl paragraph 2.

No change in 6.7 stmt.dcl paragraph 3.

Change 6.7 stmt.dcl paragraph 4:

The zero-initialization (8.5 dcl.init) of all local objects variables with static storage duration (3.7.1 basic.stc.static) or thread storage duration (3.7.2 basic.stc.thread) is performed before any other initialization takes place. ... An implementation is permitted to perform early initialization of other local objects variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize an object a variable with static or thread storage duration in namespace scope (3.6.2 basic.start.init). Otherwise such an object a variable is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. ... If control enters the declaration concurrently while the object variable is being initialized, the concurrent execution shall wait for completion of the initialization. [ Footnote: ... ] If control re-enters the declaration recursively while the object variable is being initialized, the behavior is undefined. ...
Change 6.7 stmt.dcl paragraph 5 as follows:
The destructor for a local object with static or thread storage duration will be executed if and only if the variable it was constructed. ...
Change 7.1.1 dcl.stc paragraphs 1-8 as follows:
... If thread_local appears in any declaration of an object or reference a variable it shall be present in all declarations of that object or reference entity. ...

The register specifier shall be applied only to names of objects variables declared in a block (6.3 stmt.block) or to function parameters (8.4 dcl.fct.def). It specifies that the named object variable has automatic storage duration (3.7.3 basic.stc.auto). An object A variable declared without a storage-class-specifier at block scope or declared as a function parameter has automatic storage duration by default.

A register specifier is a hint to the implementation that the object variable so declared will be heavily used. [ Note: the hint can be ignored and in most implementations it will be ignored if the address of the object variable is taken. -- end note ]

The thread_local specifier shall be applied only to the names of objects or references variables of namespace scope and to the names of objects or references variables of block scope that also specify static. It specifies that the named object or reference entity has thread storage duration (3.7.2 basic.stc.thread).

The static specifier can be applied only to names of objects variables and functions and to anonymous unions (9.5 class.union). There can be no static function declarations within a block, nor any static function parameters. A static specifier used in the declaration of an object a variable declares the object variable to have static storage duration (3.7.1 basic.stc.static), unless accompanied by the thread_local specifier, which declares the object to have thread storage duration (3.7.2 basic.stc.thread). A static specifier can be used in declarations of class members; 9.4 class.static describes its effect. For the linkage of a name declared with a static specifier, see 3.5 basic.link.

The extern specifier can be applied only to the names of objects variables and functions. The extern specifier cannot be used in the declaration of class members or function parameters. For the linkage of a name declared with an extern specifier, see 3.5 basic.link. [ Note: The extern keyword can also be used in explicit-instantiations and linkage-specifications, but it is not a storage-class-specifier in such contexts. -- end note ]

A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has internal linkage because of a previous declaration and provided it is not declared const. Objects declared const and not explicitly declared extern have internal linkage.

The linkages implied by successive declarations for a given entity shall agree. That is, within a given scope, each declaration declaring the same object variable name or the same overloading of a function name shall imply the same linkage. Each function in a given set of overloaded functions can have a different linkage, however. ...

No change required for 7.1.2 dcl.fct.spec paragraph 4:
A static local variable in an extern inline function always refers to the same object.
Change 7.1.6.4 dcl.spec.auto paragraph 1 as follows: x
The auto type-specifier signifies that the type of an object a variable being declared shall be deduced from its initializer or specified explicitly at the end of a function declarator.
Change 7.1.6.4 dcl.spec.auto paragraph 3 as follows:
Otherwise, the type of the object variable is deduced from its initializer. The name of the object variable being declared shall not appear in the initializer expression. This use of auto is allowed when declaring objects variables in a block (6.3 stmt.block), in namespace scope (3.3.6 basic.scope.namespace), and in a for-init-statement (6.5.3 stmt.for). ...
Change 7.1.6.4 dcl.spec.auto paragraph 4 as follows:
The auto type-specifier can also be used in declaring an object a variable in the condition of a selection statement...
Change 7.3.1.1 namespace.unnamed paragraph 2 as follows:
The use of the static keyword is deprecated when declaring objects variables in a namespace scope (see annex D depr); the unnamed-namespace provides a superior alternative.
Change 7.3.4 namespace.udir paragraph 6 as follows:
[ Note: in particular, the name of an object a variable, function or enumerator does not hide the name of a class or enumeration declared in a different namespace. ... ]
No change in 7.5 dcl.link paragraph 1, effectively expanding language linkage to (non-member) references.

No change in 7.6.2 dcl.align paragraph 1, effectively expanding alignment to non-member references.

Change 8 dcl.decl paragraph 1 as follows:

A declarator declares a single object variable, function, or type, within a declaration. ...
Change 8 dcl.decl paragraph 2 as follows:
The specifiers indicate the type, storage class or other properties of the objects, functions or typedefs entities being declared. The declarators specify the names of these objects, functions or typedefs entities, and (optionally) modify the type of the specifiers with operators such as * (pointer to) and () (function returning). ...
Change 8.1 dcl.name paragraph 1 as follows:
... This can be done with a type-id, which is syntactically a declaration for an object a variable or function of that type that omits the name of the object or function entity.
Change 8.5 dcl.init paragraph 1:
... The identifier designates an object or reference a variable being initialized. ...
No change in 8.5 dcl.init paragraph 2.

Change 8.5 dcl.init paragraphs 4 as follows:

The order of initialization of static objects variables with static storage duration is described in 3.6 basic.start and 6.7 stmt.dcl. -- end note ]
No change in 8.5.3 dcl.init.ref paragraph 1.

Change 9.1 class.name paragraph 2:

A class declaration introduces the class name into the scope where it is declared and hides any class, object variable, function, or other declaration of that name in an enclosing scope (3.3 basic.scope). If a class name is declared in a scope where an object a variable, function, or enumerator of the same name is also declared, then when both declarations are in scope, the class can be referred to only using an elaborated-type-specifier (3.4.4 basic.lookup.elab). ...
Change 9.4.2 class.static.data paragraph 6 as follows:
Static data members are initialized and destroyed exactly like non-local objects variables (3.6.2 basic.start.init, 3.6.3 basic.start.term).
No change in 9.8 class.local paragraph 1.

Change 10.2 class.member.lookup paragraph 4 as follows:

... [ Note: Looking up a name in an elaborated-type-specifier (3.4.4 basic.lookup.elab) or base-specifier (clause 10 class.derived), for instance, ignores all non-type declarations, while looking up a name in a nested-name-specifier (3.4.3 basic.lookup.qual) ignores function, object variable, and enumerator declarations. ...
No change to 13.4 over.over paragraph 1 bullet 1.

Change 14 temp paragraph 5 as follows:

A class template shall not have the same name as any other template, class, function, object variable, reference, enumeration, enumerator, namespace, or type in the same scope...
No change in 14.8 temp.fct.spec paragraph 2.

Change 15.5.1 except.terminate paragraph 1 bullet 4 as follows: