clanguage-lawyerdeclarationstandardsc23

Why was this sentence removed from C23?


I usually referred to C17, but decided to switch to C23.

And looking through the C23 standard, I saw that the sentence from C17 was deleted in C23:

A declaration other than a static_assert declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration

С17(6.7 #2).

Maybe this sentence was deleted because it repeats the following sentence?

A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that:

— for an object, causes storage to be reserved for that object;

— for a function, includes the function body;121)

— for an enumeration constant, is the (only) declaration of the identifier;

— for a typedef name, is the first (or only) declaration of the identifier.

C17(6.7 #5).


Solution

  • The sentence was not removed; it was changed from:

    A declaration other than a static_assert declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration.

    to:

    If a declaration other than a static_assert or attribute declaration does not include an init declarator list, its declaration specifiers shall include one of the following:

    — a struct or union specifier or enum specifier that includes a tag, with the declaration being of a form specified in 6.7.3.4 to declare that tag;

    — an enum specifier that includes an enumerator list.

    Here is a breakdown of the parts of the sentences:

    Old Text New Text Difference
    A declaration … shall declare at least a declarator (other than the parameters of a function or the members of a structure or union)… If a declaration other than a static_assert or attribute declaration does not include an init declarator list These both speak to having a declarator at the “top level” of a declaration and appear to be equivalent. The old text says there has to be a declarator, not counting those in sub-declaration (function parameters or structure/union membrers). The next text says there has to be an init-declarator-list, which is a grammar token that appears only at the top level of a declaration (not in function parameters, for example) and which must, by its grammar, contain at least one declarator.
    … other than a static_assert declaration… … other than a static_assert… declaration These are the same.
    [No mention of attribute declaration.] … other than … attribute declaration… This change allows the new [[fallthrough]]; which is a declaration in the C grammar even though it does not look like a traditional declaration. (This new “declaration” is used to indicate that falling through to a case label in a switch statement is intentional.)
    A declaration … shall declare at least… a tag … its declaration specifiers shall include… — a struct or union specifier or enum specifier that includes a tag, with the declaration being of a form specified in 6.7.3.4 to declare that tag;… The old text says the declaration must (if it does not meet one of the other criteria) must declare a tag. The new text also says it must declare a tag, but it more specifically states it must be in the declaration’s declaration-specifiers, which appear only at the “top level” in a declaration. This rules out other placement discussed below.
    A declaration … shall declare at least… the members of an enumeration… … its declaration specifiers shall include… — an enum specifier that includes an enumerator list… As above, the new text specifically states an enumerator-list, which grammatically must contain an enumerator, must appear in the declaration’s declaration-specifiers, again ruling out other placement.

    Regarding the last two items, with C 2018 wording but C 2024 features, we might sneak in a tag or enumerator declaration in an unusual place:

    _BitInt(sizeof (struct foo { int x; }));
    

    This declaration declares foo as a tag inside a sizeof expression, but it does not declare any identifier for the _BitInt type (as it would if it were _BitInt(sizeof (struct foo { int x; })) HereIsADeclarator;). The new text says you must declare at least one tag or enumeration member directly in the declaration specifiers of the declaration, which are at its “top level.” It is not enough to sneak in a declaration somewhere else.

    (Note that the struct foo is inside the declaration specifiers, since _BitInt(sizeof (struct foo { int x; })) is a declaration specifier. However, it is not “directly” in the declaration specifier. That is, it is not in a struct-or-union-specifier of the declaration-specifier. I think the C 2024 wording is weak here. The tag is declared in a struct-or-union-specifier inside the sizeof expression, which is inside the declaration’s declaration-specifier. It is not in a struct-or-union-specifier that the declaration-specifier directly translates to. So I think the standard could use a little work here.)