Proposal for C2y
WG14 3473

Title:               `if` declarations, v5
Author, affiliation: Alex Celeste, Perforce
Date:                2025-01-31
Proposal category:   Feature  improvement
Target audience:     Compiler implementers, users

Abstract

The C if statement only admits an expression as its operand. In contrast, the for statement admits either an expression or a declaration as its first operand. We propose that C modifies the if statement to allow the operand to be either a declaration or an expression, and to optionally allow a second expression clause when the first clause is a declaration. This is taken from existing practice in C++.


if declarations, v5

Reply-to:     Alex Celeste (aceleste@perforce.com)
Document No:  N3473
Revises:      N3388
Date:         2025-01-31

Summary of Changes

N3473

N3388

N3356

N3267

N3196

Introduction

This paper proposes a clarifying revision to the feature adopted into C2Y as N3356, allowing a variable to be declared in the controlling clause of a selection statement.

This revision is in response to Reflector feedback which raised two issues:

Firstly, the semantics of the "third form" (no explicit expression) were not clear enough in the case of certain storage-class specifiers. Because the wording simply said "is the value of" it was unclear how a value might be re-evaluated or re-initialized.

By providing explicit wording to guarantee that a declaration in the third form is always rewritten:

if (T x = y) { ...

// is ALWAYS the same as
if (T x = y; x) { ...

...we can clarify the intended number of evaluations and the nature of the implicit controlling expression. We can also make it explicitly implementation defined whether x is re-evaluated when volatile or atomic, rather than impose a behaviour here. This opens up space for helpful warnings.

Implicitly, this now provides a well-defined behaviour for a statement like:

if (static int once = 1) {
  once = 0;
  work (); // only called once per program
}

For the time being we suggest a Constraint against doing this in response to feedback on the Reflector. We should lift the Constraint if it becomes clear that users would understand code written this way. An equivalent to this Constraint exists in C++ as of C++23.

Secondly, it was judged to be unclear to place simple-declaration alongside the definition of declarations in general in 6.7.1, when the grammar rule does not actually define any separate kind of declaration or semantics. Therefore, the rule is moved to 6.8.5 and the wording clarifies that it is immediately rewritten into a different form that uses existing kinds of declaration semantics.

See previous revisions, and p0305, for a discussion of motivations for adding the feature, which is now part of C2Y.

Alternatives

See previous revisions for a discussion of alternatives. This feature has now been adopted into C2Y and is available in the language.

Prior Art

The feature was standardized in C++17 and is now widely used.

Compatibility

The feature standardized here differs slightly from the C++ feature by not including the C++ grammatical construct condition, which allows the second clause of if and for to be a second, completely separate declaration:

if (int x = 0; int y = x + 1) {
  y;
}

Instead of over-complicating the grammar in a single change, and confusing the change to if with largely-unrelated changes to for, we separate this aspect out and will consider aligning with this for both statement kinds in a subsequent proposal instead. Therefore, the second clause to if is limited to being an expression only in this proposal.

This was an emergent feature that users are unlikely to try to use intentionally.

The declaration-condition rule defined in this version of the wording is intended to help future changes develop this if the Committee agrees with the direction.

Impact

See previous revisions for a discussion of impact on tooling. This feature has now been adopted into C2Y.

Proposed wording

The proposed changes are based on the latest public draft of C2y, which is N3435. Bolded text is new text when inlined into an existing sentence.

Selection

Delete the simple-declaration rule from the grammar in 6.7.1 "Declarations".

Delete 6.7.1 paragraph 13 and its associated footnote 126.

Delete the forward reference to 6.8.5 from 6.7.1.

Modify the statement grammar in 6.8.5.1 "Selection statements", Syntax, paragraph 1, replacing simple-declaration with condition-declaration:

selection-header:
expression
declaration expression
declaration-condition

declaration-condition
attribute-specifier-sequenceopt declaration-specifiers declarator = initializer

(This makes failure to initialize the object in the third form a syntax error, and intentionally limits it to declaring a single object.)

Add a new paragraph to 6.8.5.1, before paragraph 2:

Constraints

Storage class specifiers other than auto, constexpr, or register shall not appear in the declaration specifiers of a declaration-condition.

Modify paragraph 3 of "Semantics" to delete the second sentence "Otherwise, ...":

If the selection-header is the first or second form, the controlling expression is the expression of the selection-header.

and add a new paragraph before paragraph 4:

A declaration-condition in the third form (with specifiers T, declarator D and initializer X), such as

T D = X

is always treated exactly as if it had been written in the second form, as

T D = X; D

except that it is implementation-defined whether D is re-evaluated for the purposes of volatile access.

Iteration

The proposed change to 6.8.6 "Iteration statements" has been removed from this feature proposal and will be revisited at a later time.

Adding a named production for declaration-condition is intended to facilitate extending the feature in this space at some later date.

Questions for WG14

This feature was adopted at the 71st WG14 meeting in Fall 2024.

Does WG14 want to adopt the changes to the existing wording that remove simple-declaration and clarify how the third form is treated?

Does WG14 want to include the constraint against other storage class specifiers in the declaration specifiers of the third form?

Acknowledgements

Huge thanks to Joseph Myers for detailed and thorough review of previous versions. Thanks to Jens Gustedt, Martin Uecker and Jakub Lukasiewicz for usability feedback.

References

C2y public draft
N740 Declarations in for
p0305r1 Selection statements with initializer
Anaphoric macros
Example of just and expect
C++17