2022-04-08
org: | ISO/IEC JCT1/SC22/WG14 | document: | N2952 | |
target: | IS 9899:2023 | version: | 1 | |
date: | 2022-04-08 | license: | CC BY |
Paper number | Title | Changes |
---|---|---|
N2952 | Underspecified object declarations | common introduction replacing previous |
N2890 type-generic programming | ||
N2917 The constexpr specifier |
N2890 (type-generic programming) and N2917 (the constexpr
specifier) proposed new features to C that are already much experienced in other programming languages. Whereas WG14 found current integration of the proposed features for functional extension into C insufficient, we voted in favor of an integration of features when they reduced to object declarations:
constexpr
object features for C23These features are syntactically and semantically closely related and so we decided to join efforts such that we may provide a seamless integration of both into C23.
N2952: Underspecified object declarations
This paper. It provides an introduction and proposes a common syntactic feature that serves for the introduction of both target features, namely underspecified declarations.
N2953: Type inference for object definitions
This proposes type inference for object declarations, by either using the existing __auto_type
extension (gcc, clang) or the portage of the extension to the auto
keyword as imported from C++ (clang).
N2954: The constexpr specifier for object definitions
This reduces the proposed constexpr
feature to objects and resolves some issues that remained with the specification of such a feature.
N2955: Introduce storage-class specifiers for compound literals
This adds the possibility to add storage-class specifiers such as constexpr
and static
to compound literals.
The later three become thus much simpler and hopefully less contested.
#include <tgmath.h>
constexpr double π = 3.1415926536; // floating point constants
constexpr char const empty[] = ""; // named string constants
auto n = 4294967296u; // obtain implementation-defined type
auto r = cos(x); // infer consistent type
The features have several properties in common
they need an initializer before the object can be used in any way
use of the declared identifier within the initializer causes a cycle in the type or value dependency
using them with several declarators in the same declaration could cause unnecessary ambiguity that is best avoided
declaring non-ordinary identifiers such as tags or member names would complexify specification
auto n = 4294967296u;
int main() {
auto k; // invalid
auto alignof(n) n = 44; // valid, refers to outer
auto n = n; // invalid, refers to inner, cyclic
auto n = 4294967296u, m = 4294967297u; // same types ?
auto x = (struct s {int a; }){ }; // confusion of scope for struct s
struct s {int a; } x; // clearly a local type definition
}
Storage-class specifier as a term becomes even more a misnomer with the features that are introduced in this series of papers. In fact they then specify
static
in block scope, auto
, register
, thread_local
)static
in file scope, extern
)register
)constexpr
)typedef
, __auto_type
or auto
)Their possible combination is as indicated in the following table:
co | at | au | re | tl | st | ex | il | td | |
---|---|---|---|---|---|---|---|---|---|
constexpr |
➕ | ➕ | ➕ | ➕ | |||||
__auto_type |
➕ | ➕ | ➕ | ➕ | ➕ | ➕ | |||
auto |
➕ | ➕ | |||||||
register |
➕ | ➕ | |||||||
thread_local |
➕ | ✅ | ✅ | ||||||
static |
➕ | ➕ | ✅ | ✅ | |||||
extern |
➕ | ✅ | ✅ | ||||||
inline |
✅ | ✅ | ✅ | ||||||
typedef |
It might be worth considering to rename the term “storage-class specifier” editorially to something that fits better, such as “declaration specifier”, and to fuse it with the term “function specifier” (inline
and _Noreturn
).
WG14 would not have to vote on the proposed changes individually, but only in combination with N2953 and N2954.
The term underspecified declaration is introduced in a new paragraph at the end of 6.7. Depending on the features that WG14 accepts for C23 one of the following three alternatives should be used.
constexpr
is said to be underspecified.
constexpr
is said to be underspecified.
The property that the identifier under declaration should not be visible within the initializer is best modeled by adjusting the scope in which it is visible. Therefore we amend 6.2.1 p7 with special rules that ensure that
Identifiers of a surrounding scope remain visible until the end of the declarator (that is up to the =
of the initializer)
The declared initializer is only visible after the whole declaration is completed.
7 Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag. Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list. An ordinary identifier that has an underspecified definition has scope that starts when the definition is completed; if the same ordinary identifier declares another entity with a scope that encloses the current block, that declaration is hidden as soon as the inner declarator is completed.FNT) Any other identifier has scope that begins just after the completion of its declarator.
FNT) That means, that the outer declaration is not visible for the initializer.
An underspecified declaration should declare exactly one ordinary identifier, no structure ore union tags or members or any other collaterals such as enumeration constants. This is achieved by two additions.
4’ In an underspecified declaration all declared identifiers that do not have a prior declaration shall be ordinary identifiers.
If such a declaration is not a definition, if it declares no or more than one ordinary identifier, or if the declared entity is not an object, the behavior is undefined.
For the latter the choice is to go with UB, because there are already extensions that go beyond the definitions as given here, such as auto
declarations of several variables or constexpr
functions.
Adapt p6 such that it better reflects on the effective role of storage-class specifiers
6
TheStorage-class specifiers specify various properties of identifiers and declared features; storage duration (typedef
specifier is called a “storage-class specifier” for syntactic convenience only; it is discussed in 6.7.8.static
in block scope,thread_local
,auto
,register
), linkage (extern
,static
in file scope,typedef
) and type (typedef
). The meanings of the various linkages and storage durations were discussed in 6.2.2 and 6.2.4,typedef
is discussed in 6.7.8.