2022-07-21
org: | ISO/IEC JCT1/SC22/WG14 | document: | N3038 |
target: | IS 9899:2023 | ||
date: | 2022-07-21 | license: | CC BY |
We propose adding storage-class specifiers such as constexpr
or static
to compound literals such that this feature gains the full semantic capacities as have declared objects.
thread_local
to the list because we voted that inCurrently, the feature of compound literals does not have the capacity to express all aspects that ordinary object definitions have.
Recently and independently two papers expressed the idea to extend the current syntax of compound literals such that storage-class specifiers can be used as if for the definition of an object.
constexpr
such that such compound literals potentially can be used anywhere as a constant expression of the appropriate kind. For a rationale for that we refer to that paper and more generally to N3018 which introduces the constexpr
feature as such.
For this paper here, we thus propose to extend the feature with a list of possible storage-class specifiers, namely static
, register
and constexpr
. Other possible additions concern thread_local
, auto
or __auto_type
. We leave it to WG14 to determine the list of admissible specifiers.
Syntactically this is just done by allowing to prefix the type name of the compound literal by a list of these storage-class specifiers.
GNU C (and followed by IBM XL C for compatibility) already allows the use of compound literals for the initialization of objects with static storage duration such as in
static struct foo x = (struct foo) {1, 'a', 'b'}; // initialize with a value, need not be modifiable
If this is found inside a block (and not in file scope) the compound literal has automatic storage duration and would thus not be suitable as initializer for static
variables. GNU C gets away with this by extending the definition of constant expression to “compound literals where all initializer expressions are constant expressions”.
This feature does not give syntactic control to the user for this construct; it could just be an error for which the user would like to have a diagnostic. Our proposal, when using constexpr
makes this feature explicit.
static struct foo x = (constexpr struct foo) {1, 'a', 'b'}; // initialize with a value, need not be modifiable
The same feature for gcc when we take the address of the compound literal is not allowed
static struct foo* p = &(struct foo) {1, 'a', 'b'}; // initialize with an address, target modifiable
and produces an error that the intializer is not constant. So for gcc the expression (struct foo) {1, 'a', 'b'}
is constant in some places and others isn’t.
The only way around this in C17 is to use a static
variable
static struct foo Unique = (struct foo) {1, 'a', 'b'}; // initialize with a value, need not be modifiable
static struct foo* p = &Unique; // initialize with an address, target modifiable
Our proposal avoids a declaration of a variable that is otherwise unused.
static struct foo* p = &(static struct foo) {1, 'a', 'b'}; // initialize with an address, target modifiable
The proposal is based on N3018 and N2819 (already voted into C23).
1 postfix-expression:
primary-expression
postfix-expression
[
expression]
postfix-expression
(
argument-expression-listopt)
postfix-expression
.
identifier
postfix-expression
->
identifier
postfix-expression
++
postfix-expression
--
(
type-name)
{
initializer-list{.C}}
(
type-name)
{
initializer-list{.C},
{.C}}
compound-literal
Add a whole new syntax section
Syntax
1’ compound-literal:
(
storage-class-specifiersopt type-name)
{
initializer-listopt{.C}}
(
storage-class-specifiersopt type-name)
{
initializer-list{.C},
{.C}}
storage-class-specifiers:
storage-class-specifier
storage-class-specifiers storage-class-specifier
Add a paragraph and footnote at the end of the constraint section.
2’ If the compound literal is evaluated outside the body of a function and outside of any parameter list, it is associated with file scope; otherwise, it is associated with the enclosing block. Depending on this association, the storage-class specifiers
SC
(possibly empty),FNT0) type nameT
, and initializer list, if any, shall be such that they are valid specifiers for an object definition in file scope or block scope, respectively, of the following form,
typeof(T) ID = { IL }; SC
where
ID
is an identifier that is unique for the whole program and whereIL
is a (possibly empty) initializer list with nested structure, designators, values and types as the initializer list of the compound literal. All the constraints for storage class specifiers in 6.7.1 also apply to compound literals
FNT0) If the storage-class specifiers contain the same storage-class specifier more than once, the following constraint is violated.
Remove the textual definition and add words for the storage-class specifiers.
3 A
postfix expression that consists of a parenthesized type name followed by a brace-enclosed list of initializers is acompound literalItprovides an unnamed object whose valueis given by the initializer list, type, storage duration and other properties are as if given by the definition syntax in the constraints; if the storage duration is automatic, the lifetime of the instance of the unnamed object is the current execution of the enclosing block.107) If the storage-class specifiers contain other specifiers thanconstexpr
,static
,register
, orthread_local
the behavior is undefined.
4 If the type name specifies an array of unknown size, the size is determined by the initializer list as specified in 6.7.9, and the type of the compound literal is that of the completed array type. Otherwise (when the type name specifies an object type), the type of the compound literal is that specified by the type name. In either case, the result is an lvalue.
5 The value of the compound literal is that of an lvalue corresponding to the
anunnamed objectinitialized by the initializer list. If the compound literal is evaluated outside the body of a function and outside of any parameter list, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block. If it is evaluated for a function call to determine the variably modified type of a parameter it has a lifetime that starts with the evaluation and that ends with the end of the execution of the call.
If the list of admissible storage-class specifiers for compound literals contains constexpr
, add to the new paragraph 6
6 An identifier that is declared with storage-class specifier
constexpr
and an object type is a named constant. A named constant is a constant expression with the type and value of the declared object. A compound literal with storage-class specifierconstexpr
is a compound literal constant. A compound literal constant is a constant expression with the type and value of the unnamed object.
Then, in the following three paragraphs (integer expressions, initializers, arithmetic expression) where “named constant” appears in the list, replace by “named constant or compound literal constant”.
Does WG14 want to add the changes as indicated in N3038 into C23?
Does WG14 want to add the
thread_local
storage-class specifier to the list of admissible storage-class specifiers for compound literals for integration into C23?
Does WG14 want to add the
auto
storage-class specifier to the list of admissible storage-class specifiers for compound literals for integration into C23?
Does WG14 want to add the
__auto_type
storage-class specifier to the list of admissible storage-class specifiers for compound literals for integration into C23?