# Underspecified object declarations

2022-04-08

 org: ISO/IEC JCT1/SC22/WG14 document: N2952 target: IS 9899:2023 version: 1 date: 2022-04-08 license: CC BY

## Revision history

Paper number Title Changes
N2952 Underspecified object declarations common introduction replacing previous
N2890 type-generic programming
N2917 The constexpr specifier

## Introduction

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:

• 11/4/8 WG14 wants the constexpr object features for C23
• 10/6/1 WG14 wants something along the lines of N2923 for auto objects in C23

These 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.

### Examples

#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

## Common syntax requirements

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

### Examples

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
}

## Interaction between storage-class specifiers

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

• storage duration (static in block scope, auto, register, thread_local)
• linkage (static in file scope, extern)
• addressablity (register)
• compile time determination (constexpr)
• types (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).

## Design

WG14 would not have to vote on the proposed changes individually, but only in combination with N2953 and N2954.

### Terminology

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.

Alternatives:
A declaration such that the declaration specifiers contain no type specifier or that is declared with constexpr is said to be underspecified.
A declaration such that the declaration specifiers contain no type specifier is said to be underspecified.
A declaration with constexpr is said to be underspecified.

### Scope of identifiers

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.

### Other identifiers

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.

• A constraint that forbids to declare identifiers from any other name space than the ordinary identifier name space (6.7 new para after p4)
4’ In an underspecified declaration all declared identifiers that do not have a prior declaration shall be ordinary identifiers.
• UB that forces a definition of an object and forbids to have other than exactly one identifier declared (appended to the new para at the end of 6.7)
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.

### Storage-class specifiers (6.7.1)

Adapt p6 such that it better reflects on the effective role of storage-class specifiers

6 The typedef specifier is called a “storage-class specifier” for syntactic convenience only; it is discussed in 6.7.8.Storage-class specifiers specify various properties of identifiers and declared features; storage duration (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.