Primary expressions and constant expressions

2022-04-24

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

Abstract

When preparing the recent proposals for changes to constant expressions (keywords false and true, constexpr and nullptr) it came to me that the text on primary expressions is not completely clear concerning the specialized properties of expressions that the standard knows about. The general idea is that these propagate well through primary expressions, but the current text only mentions lvalues, function designators and void expressions explicitly.

There are more properties that give special status to expressions, namely being a constant expression, an integer constant expression, an arithmetic constant expression, an address constant, or a null pointer constant. I don’t think that anybody gets these wrong, but nevertheless it might be worth to add words to the text that make this explicit.

Besides constant expression, these special properties are not defined as syntax terms but only as derived terms. In particular, all appearances (except one) in the syntax of the term constant-expression then have explicit constraints that these in fact are integer constant expressions. It appeared to me that the understanding of the text could be much easier if that property would immediately follow from the syntax.

Impact

This is intended for clarification. Only one, separated, normative change is implied. For the latter a separate poll is taken.

Proposed wording

Changes are proposed against the wording in C23 draft n2731 with the changes for keywords added. Some of the other recent proposal may textually interact or even conflict with the proposal, here, but these should be resolvable by editorial decisions, only.

Primary expressions (6.5.1)

change p5

5 A parenthesized expression is a primary expression. Its type and value are identical to those of the unparenthesized expression. It is a constant expression, an integer constant expression, an arithmetic constant expression, an address constant, a null pointer constant, an lvalue, a function designator, or a void expression if the unparenthesized expression is, respectively, a constant expression, an integer constant expression, an arithmetic constant expression, an address constant, a null pointer constant, an lvalue, a function designator, or a void expression.

Generic selection (6.5.1.1)

change p4

4 The type and value of a generic selection are identical to those of its result expression. It is a constant expression, an integer constant expression, an arithmetic constant expression, an address constant, a null pointer constant, an lvalue, a function designator, or a void expression if its result expression is, respectively, a constant expression, an integer constant expression, an arithmetic constant expression, an address constant, a null pointer constant, an lvalue, a function designator, or a void expression.

Constant expressions (6.6)

Syntax

1 constant-expression:

conditional-expression

integer-constant-expression:

constant-expression

arithmetic-constant-expression:

constant-expression

constant-expression

null-pointer-constant:

constant-expression

Description

2 A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be. Null pointer constants have been described in 6.3.2.3.

Bitfields (6.7.2.1)

member-declarator:

declarator

declaratoropt : integer-constant-expression

Enumerator specifiers (6.7.2.2)

enumerator:

enumeration-constant attribute-specifier-sequenceopt

enumeration-constant attribute-specifier-sequenceopt = integer-constant-expression

Constraints

2 The integer constant expression that defines the value of an enumeration constant shall be an integer constant expression that hashave a value representable as an int.

Alignment specifier (6.7.5)

Syntax

1 alignment-specifier:

_Alignas ( type-name )

_Alignas ( integer-constant-expression )

Constraints

2 An alignment specifier shall appear only in the declaration specifiers of a declaration, or in the specifier-qualifier list of a member declaration, or in the type name of a compound literal. An alignment specifier shall not be used in conjunction with either of the storage-class specifiers typedef or register, nor in a declaration of a function or bit-field.

3 The integer constant expression shall be an integer constant expression. It shall evaluate to a valid fundamental alignment, or to a valid extended alignment supported by the implementation for an object of the storage duration (if any) being declared, or to zero.

Initialization (6.7.9)

in p1 modify

designator:

[ integer-constant-expression ]

. identifier

modify p6

6 If a designator has the form

[ integer-constant-expression ]

then the current object (defined below) shall have array type and the expression shall be an integer constant expression. If the array is of unknown size, any nonnegative value is valid.

Case labels (6.8.1)

Syntax

1 label:

attribute-specifier-sequenceopt identifier :

attribute-specifier-sequenceopt case integer-constant-expression :

attribute-specifier-sequenceopt default :

labeled-statement:

label statement

The switch statement (6.8.4.2)

change p3

3 The expression of each case label shall be an integer constant expression and n No two of the case integer constant expressions in the same switch statement shall have the same value after conversion. There may be at most one default label in a switch statement. (Any enclosed switch statement may have a default label or case integer constant expressions with values that duplicate case integer constant expressions in the enclosing switch statement.)

change p5

5 The integer promotions are performed on the controlling expression. The integer constant expression in each case label is converted to the promoted type of the controlling expression. If a converted value matches that of the promoted controlling expression, control jumps to the statement following the matched case label. Otherwise, if there is a default label, control jumps to the statement following the default label. If no converted case constant expression matches and there is no default label, no part of the switch body is executed.

Preprocessing directives (6.10)

change in p1

if-group:

# if integer-constant-expression new-line groupopt

# ifdef identifier new-line groupopt

# ifndef identifier new-line groupopt

elif-groups:

elif-group

elif-groups elif-group

elif-group:

# elif integer-constant-expression new-line groupopt

# elifdef identifier new-line groupopt

# elifndef identifier new-line groupopt

Conditional inclusion (6.10.1)

change p6

6 Preprocessing directives of the forms

# if integer-constant-expression new-line groupopt

# elif integer-constant-expression new-line groupopt

check whether the controlling integer constant expression evaluates to nonzero.

and change the term

controlling integer constant expression

where it occurs.

Static assertion (6.7.10)

For static assertions the situation is a bit different because the requirement to be an integer constant expression is not formulated as a constraint; if the expression is not an integer constant expression the behavior is undefined.

This a divergence with C++, which allows all constant expressions that are convertible to bool. If WG14 would aggree to this change, this would be a normative change, although this would only affect existing implementations, not existing code.

On the other hand, it would reduce the number of cases for which C and C++ are different. This would a win, since this is a feature that C copied from C++.

Syntax

1 static_assert-declaration:

static_assert ( constant-expression , string-literal ) ;

static_assert ( constant-expression ) ;

Constraints

2 The constant expression shall compare unequal to 0.

Semantics

3 The constant expression shall be an integer constant expression. If the value of the constant expression compares unequal to 0, the declaration has no effect. Otherwise, the constraint is violated and the implementation shall produce a diagnostic message which should include the text of the string literal, if present.

Questions to WG14

Does WG14 want to integrate the changes for primary expressions, 3.1 and 3.2 of N2980, into C23?

Does WG14 want to integrate the changes for constant expression, 3.3 to 3.11 of N2980, into C23?

Does WG14 want to integrate the change for static_assert, 3.12 of N2980, into C23?