[stmt.stmt] (original) (raw)
8 Statements [stmt.stmt]
8.1 Preamble [stmt.pre]
A substatement of a statement is one of the following:
- for a labeled-statement, its contained statement,
- for a compound-statement, any statement of its statement-seq,
- for a selection-statement, any of its statements (but not its init-statement), or
- for an iteration-statement, its contained statement (but not an init-statement).
A statement S1 enclosesa statement S2 if
- S2 is a substatement of S1 ([dcl.dcl]),
- S1 is a selection-statement oriteration-statement andS2 is the init-statement of S1,
- S1 is a try-block and S2 is its compound-statement or any of the compound-statements of its handlers, or
- S1 encloses a statement S3 and S3 encloses S2.
The rules for conditions apply both toselection-statements and to the for and whilestatements ([stmt.iter]).
The declarator shall not specify a function or an array.
[ Note
:
A name introduced in a selection-statement oriteration-statement outside of any substatement is in scope from its point of declaration until the end of the statement's substatements.
Such a name cannot be redeclared in the outermost block of any of the substatements ([basic.scope.block]).
— end note
]
The value of a condition that is an initialized declaration in a statement other than a switch statement is the value of the declared variablecontextually converted to bool.
If that conversion is ill-formed, the program is ill-formed.
The value of acondition that is an initialized declaration in aswitch statement is the value of the declared variable if it has integral or enumeration type, or of that variable implicitly converted to integral or enumeration type otherwise.
The value of acondition that is an expression is the value of the expression, contextually converted to boolfor statements other than switch; if that conversion is ill-formed, the program is ill-formed.
The value of the condition will be referred to as simply “the condition” where the usage is unambiguous.
If a condition can be syntactically resolved as either an expression or the declaration of a block-scope name, it is interpreted as a declaration.
8.2 Labeled statement [stmt.label]
A statement can be labeled.
labeled-statement: attribute-specifier-seq identifier : statement attribute-specifier-seq case constant-expression : statement attribute-specifier-seq default : statement
Anidentifier label declares the identifier.
The only use of an identifier label is as the target of agoto.
The scope of a label is the function in which it appears.
Labels shall not be redeclared within a function.
A label can be used in agoto statement before its declaration.
Labels have their own name space and do not interfere with other identifiers.
[ Note
:
A label may have the same name as another declaration in the same scope or atemplate-parameter from an enclosing scope.
— end note
]
Case labels and default labels shall occur only in switch statements.
8.3 Expression statement [stmt.expr]
Allside effects from an expression statement are completed before the next statement is executed.
An expression statement with the expression missing is called a null statement.
[ Note
:
Most statements are expression statements — usually assignments or function calls.
A null statement is useful to carry a label just before the } of a compound statement and to supply a null body to an iteration statement such as a whilestatement.
— end note
]
8.4 Compound statement or block [stmt.block]
So that several statements can be used where one is expected, the compound statement (also, and equivalently, called “block”) is provided.
compound-statement: { statement-seq }
statement-seq: statement statement-seq statement
[ Note
:
A declaration is a statement ([stmt.dcl]).
— end note
]
8.5 Selection statements [stmt.select]
Selection statements choose one of several flows of control.
selection-statement: if constexpr ( init-statement condition ) statement if constexpr ( init-statement condition ) statement else statement switch ( init-statement condition ) statement
[ Note
:
An init-statement ends with a semicolon.
— end note
]
The substatement in a selection-statement (each substatement, in the else form of the if statement) implicitly defines a block scope ([basic.scope]).
If the substatement in aselection-statement is a single statement and not acompound-statement, it is as if it was rewritten to be acompound-statement containing the original substatement.
[ Example
:
if (x) int i;
can be equivalently rewritten as
if (x) { int i; }
Thus after the if statement, i is no longer in scope.
— end example
]
8.5.1 The if statement [stmt.if]
If the condition ([stmt.select]) yields true the first substatement is executed.
If the else part of the selection statement is present and the condition yields false, the second substatement is executed.
If the first substatement is reached via a label, the condition is not evaluated and the second substatement is not executed.
In the second form of if statement (the one including else), if the first substatement is also anif statement then that inner if statement shall contain an else part.83
If the value of the converted condition is false, the first substatement is adiscarded statement, otherwise the second substatement, if present, is a discarded statement.
During the instantiation of an enclosing templated entity ([temp.pre]), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.
[ Note
:
Odr-uses in a discarded statement do not require an entity to be defined.
— end note
]
A case or default label appearing within such anif statement shall be associated with a switchstatement within the same if statement.
A label declared in a substatement of a constexpr if statement shall only be referred to by a statement in the same substatement.
[ Example
:
template<typename T, typename ... Rest> void g(T&& p, Rest&& ...rs) {
if constexpr (sizeof...(rs) > 0)
g(rs...);
}
extern int x;
int f() { if constexpr (true) return 0; else if (x) return x; else return -x; }
— end example
]
An if statement of the form
if constexpr ( init-statement condition ) statement
is equivalent to
{ init-statement if constexpr ( condition ) statement }
and an if statement of the form
if constexpr ( init-statement condition ) statement else statement
is equivalent to
{ init-statement if constexpr ( condition ) statement else statement }
except that names declared in the init-statement are in the same declarative region as those declared in thecondition.
8.5.2 The switch statement [stmt.switch]
The switch statement causes control to be transferred to one of several statements depending on the value of a condition.
The condition shall be of integral type, enumeration type, or class type.
If the (possibly converted) type is subject to integral promotions, the condition is converted to the promoted type.
No two of the case constants in the same switch shall have the same value after conversion.
There shall be at most one label of the form
default :
within a switch statement.
Switch statements can be nested; a case or default label is associated with the smallest switch enclosing it.
When the switch statement is executed, its condition is evaluated.
If one of the case constants has the same value as the condition, control is passed to the statement following the matched case label.
If no case constant matches the condition, and if there is adefault label, control passes to the statement labeled by the default label.
If no case matches and if there is no defaultthen none of the statements in the switch is executed.
case and default labels in themselves do not alter the flow of control, which continues unimpeded across such labels.
To exit from a switch, see break.
[ Note
:
Usually, the substatement that is the subject of a switch is compound and case and default labels appear on the top-level statements contained within the (compound) substatement, but this is not required.
Declarations can appear in the substatement of aswitch statement.
— end note
]
A switch statement of the form
switch ( init-statement condition ) statement
is equivalent to
{ init-statement switch ( condition ) statement }
except that names declared in the init-statement are in the same declarative region as those declared in thecondition.
8.6 Iteration statements [stmt.iter]
The substatement in an iteration-statement implicitly defines a block scope which is entered and exited each time through the loop.
If the substatement in an iteration-statement is a single statement and not a compound-statement, it is as if it was rewritten to be a compound-statement containing the original statement.
[ Example
:
while (--x >= 0) int i;
can be equivalently rewritten as
while (--x >= 0) { int i; }
Thus after the while statement, i is no longer in scope.
— end example
]
If a name introduced in aninit-statement or for-range-declarationis redeclared in the outermost block of the substatement, the program is ill-formed.
[ Example
:
void f() {
for (int i = 0; i < 10; ++i)
int i = 0;
for (int i : { 1, 2, 3 })
int i = 1;
}
— end example
]
8.6.1 The while statement [stmt.while]
In the while statement the substatement is executed repeatedly until the value of the condition ([stmt.select]) becomesfalse.
The test takes place before each execution of the substatement.
When the condition of a while statement is a declaration, the scope of the variable that is declared extends from its point of declaration ([basic.scope.pdecl]) to the end of the while statement.
A while statement is equivalent to
label : { if ( condition ) { statement goto label ; } }
[ Note
: The variable created in the condition is destroyed and created with each iteration of the loop.
[ Example
:
struct A { int val; A(int i) : val(i) { } ~A() { } operator bool() { return val != 0; } }; int i = 1; while (A a = i) {
i = 0; }
In the while-loop, the constructor and destructor are each called twice, once for the condition that succeeds and once for the condition that fails. — end example
]
— end note
]
8.6.2 The do statement [stmt.do]
In the do statement the substatement is executed repeatedly until the value of the expression becomes false.
The test takes place after each execution of the statement.
8.6.3 The for statement [stmt.for]
The for statement
for ( init-statement condition ; expression ) statement
is equivalent to
{ init-statement while ( condition ) { statement expression ; } }
except that names declared in the init-statement are in the same declarative region as those declared in thecondition, and except that acontinue in statement (not enclosed in another iteration statement) will execute expression before re-evaluating condition.
[ Note
:
Thus the first statement specifies initialization for the loop; the condition ([stmt.select]) specifies a test, sequenced before each iteration, such that the loop is exited when the condition becomesfalse; the expression often specifies incrementing that is sequenced after each iteration.
— end note
]
Either or both of the conditionand the expression can be omitted.
A missing conditionmakes the implied while clause equivalent to while(true).
If the init-statement is a declaration, the scope of the name(s) declared extends to the end of the for statement.
[ Example
:
int i = 42; int a[10];
for (int i = 0; i < 10; i++) a[i] = i;
int j = i;
— end example
]
8.6.4 The range-based for statement [stmt.ranged]
The range-based for statement
for ( init-statement for-range-declaration : for-range-initializer ) statement
is equivalent to
{ init-statement auto &&range = for-range-initializer ; auto begin = begin-expr ; auto end = end-expr ; for ( ; begin != end; ++begin ) { for-range-declaration = * begin ; statement } }
where
- if the for-range-initializer is an expression, it is regarded as if it were surrounded by parentheses (so that a comma operator cannot be reinterpreted as delimiting two init-declarators);
- range, begin, and end are variables defined for exposition only; and
- begin-expr and end-expr are determined as follows:
- if the for-range-initializer is an expression of array type R, begin-expr and end-expr arerange and range + N, respectively, where N is the array bound. If R is an array of unknown bound or an array of incomplete type, the program is ill-formed;
- if the for-range-initializer is an expression of class type C, the unqualified-ids begin and end are looked up in the scope of Cas if by class member access lookup ([basic.lookup.classref]), and if both find at least one declaration, begin-expr andend-expr are range.begin() and range.end(), respectively;
- otherwise, begin-expr and end-expr arebegin(range) and end(range), respectively, where begin and end are looked up in the associated namespaces ([basic.lookup.argdep]).
[ Example
:
int array[5] = { 1, 2, 3, 4, 5 }; for (int& x : array) x *= 2;
— end example
]
8.7 Jump statements [stmt.jump]
On exit from a scope (however accomplished), objects with automatic storage duration that have been constructed in that scope are destroyed in the reverse order of their construction.
Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of objects with automatic storage duration that are in scope at the point transferred from but not at the point transferred to.
(See [stmt.dcl] for transfers into blocks).
[ Note
:
However, the program can be terminated (by callingstd::exit() orstd::abort() ([support.start.term]), for example) without destroying objects with automatic storage duration.
— end note
]
[ Note
:
A suspension of a coroutine ([expr.await]) is not considered to be an exit from a scope.
— end note
]
8.7.1 The break statement [stmt.break]
The break statement shall occur only in aniteration-statement or a switch statement and causes termination of the smallest enclosing iteration-statement orswitch statement; control passes to the statement following the terminated statement, if any.
8.7.2 The continue statement [stmt.cont]
Thecontinuestatement shall occur only in aniteration-statementand causes control to pass to the loop-continuation portion of the smallest enclosing iteration-statement, that is, to the end of the loop.
More precisely, in each of the statements
while (foo) { {
} contin: ; }
do { {
} contin: ; } while (foo);
for (;;) { {
} contin: ; }
a continue not contained in an enclosed iteration statement is equivalent to goto contin.
8.7.3 The return statement [stmt.return]
A function returns to its caller by the return statement.
A return statement with no operand shall be used only in a function whose return type iscv void, a constructor, or adestructor.
A return statement with an operand of type void shall be used only in a function whose return type is cv void.
A return statement with any other operand shall be used only in a function whose return type is not cv void;the return statement initializes the glvalue result or prvalue result object of the (explicit or implicit) function call by copy-initialization from the operand.
[ Note
:
A return statement can involve an invocation of a constructor to perform a copy or move of the operand if it is not a prvalue or if its type differs from the return type of the function.
A copy operation associated with a return statement may be elided or converted to a move operation if an automatic storage duration variable is returned ([class.copy.elision]).
— end note
]
[ Example
:
std::pairstd::string,int f(const char* p, int x) { return {p,x}; }
— end example
]
[ Example
:
class A { ~A() {} }; A f() { return A(); }
— end example
]
Flowing off the end of a constructor, a destructor, or a non-coroutine function with a cv void return type is equivalent to a return with no operand.
Otherwise, flowing off the end of a function other than main or a coroutine ([dcl.fct.def.coroutine]) results in undefined behavior.
The copy-initialization of the result of the call is sequenced before the destruction of temporaries at the end of the full-expression established by the operand of the return statement, which, in turn, is sequenced before the destruction of local variables ([stmt.jump]) of the block enclosing the return statement.
8.7.4 The co_return statement [stmt.return.coroutine]
coroutine-return-statement: co_return expr-or-braced-init-list ;
A coroutine shall not enclose a return statement ([stmt.return]).
[ Note
:
For this determination, it is irrelevant whether the return statement is enclosed by a discarded statement ([stmt.if]).
— end note
]
A co_return statement is equivalent to:
{ S; goto final-suspend; }
where final-suspend is the exposition-only label defined in [dcl.fct.def.coroutine]and S is defined as follows:
- If the operand is a braced-init-list or an expression of non-void type,S is p.return_value(expr-or-braced-init-list). The expression S shall be a prvalue of type void.
- Otherwise,S is the compound-statement { expression ; p.return_void(); }. The expression p.return_void()shall be a prvalue of type void.
If p.return_void() is a valid expression, flowing off the end of a coroutine is equivalent to a co_return with no operand; otherwise flowing off the end of a coroutine results in undefined behavior.
8.7.5 The goto statement [stmt.goto]
The goto statement unconditionally transfers control to the statement labeled by the identifier.
The identifier shall be alabel located in the current function.
8.8 Declaration statement [stmt.dcl]
A declaration statement introduces one or more new identifiers into a block; it has the form
declaration-statement: block-declaration
If an identifier introduced by a declaration was previously declared in an outer block,the outer declaration is hidden for the remainder of the block, after which it resumes its force.
Variables with automatic storage duration declared in the block are destroyed on exit from the block ([stmt.jump]).
It is possible to transfer into a block, but not in a way that bypasses declarations with initialization (including ones in conditions and init-statements).
A program that jumps84from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has vacuous initialization ([basic.life]).
In such a case, the variables with vacuous initialization are constructed in the order of their declaration.
[ Example
:
void f() {
goto lx;
ly: X a = 1;
lx: goto ly;
}
— end example
]
Dynamic initialization of a block-scope variable withstatic storage duration orthread storage duration is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization.
If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration.
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.85
If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.
[ Example
:
int foo(int i) {
static int s = foo(2*i);
return i+1;
}
— end example
]
A block-scope object with static or thread storage duration will be destroyed if and only if it was constructed.
[ Note
:
[basic.start.term] describes the order in which block-scope objects with static and thread storage duration are destroyed.
— end note
]
8.9 Ambiguity resolution [stmt.ambig]
[ Note
:
If the statement cannot syntactically be adeclaration, there is no ambiguity, so this rule does not apply.
The whole statement might need to be examined to determine whether this is the case.
This resolves the meaning of many examples.
[ Example
:
T(a)->m = 7;
T(a)++;
T(a,5)<<c;
T(*d)(int);
T(e)[5];
T(f) = { 1, 2 };
T(*g)(double(3));
In the last example above, g, which is a pointer to T, is initialized to double(3).
This is of course ill-formed for semantic reasons, but that does not affect the syntactic analysis.
— end example
]
[ Example
:
class T {
public:
T();
T(int);
T(int, int);
};
T(a);
T(*b)();
T(c)=7;
T(d),e,f=3;
extern int h;
T(g)(h,2);
— end example
]
— end note
]
The disambiguation is purely syntactic; that is, the meaning of the names occurring in such a statement, beyond whether they aretype-names or not, is not generally used in or changed by the disambiguation.
Class templates are instantiated as necessary to determine if a qualified name is a type-name.
Disambiguation precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration.
If, during parsing, a name in a template parameter is bound differently than it would be bound during a trial parse, the program is ill-formed.
No diagnostic is required.
[ Note
:
This can occur only when the name is declared earlier in the declaration.
— end note
]
[ Example
:
struct T1 { T1 operator()(int x) { return T1(x); } int operator=(int x) { return x; } T1(int) { } }; struct T2 { T2(int){ } }; int a, (*(*b)(T2))(int), c, d;
void f() {
T1(a) = 3,
T2(4),
(*(*b)(T2(c)))(int(d));
}
— end example
]