#include <iostream>
int main(){
int b = 2;
if(int a = 0){ // #condition
}else if(b == 2){
int a; //#1
}
}
The above code can be compiled in both gcc and clang. However, according to what the relevant rules say, this code should be ill-formed. The rules are:
stmt.stmt#3
A name introduced by a declaration in a condition (either introduced by the decl-specifier-seq or the declarator of the condition) is in scope from its point of declaration until the end of the substatements controlled by the condition. If the name is redeclared in the outermost block of a substatement controlled by the condition, the declaration that redeclares the name is ill-formed.
Isn't the if-statement which follows the else
not a substatement controlled by the condition? (i.e, only the condition at #condition
executed to be false
will the if-statement after else
be executed). So, why a declaration that redeclares the name in the outermost block of such a substatement can be considered as a well-formed code?
Maybe there are some arguments for the phrase "substatement controlled by the condition" in that rules of version n4659
, however, such an idea is obviously clear in the latest draft.
stmt.stmt#stmt.pre-2
A substatement of a statement is one of the following:
for a selection-statement, any of its statements (but not its init-statement)
That means the statement after else
is a substatement of the primary if-statement
, then the next rules say that:
stmt.stmt#stmt.pre-5
A name introduced in a selection-statement or iteration-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
The rule obviously says that we cannot redeclared the same name as that declared in condition in the outermost block of these substatements. So, I'm curious whether I have misunderstood these rules or there are some defectives in the draft?
No.
You're missing the block scope introduced by the else
substatement:
[stmt.selected.general/2]
: The substatement in a selection-statement (each substatement, in theelse
form of theif
statement) implicitly defines a block scope ([basic.scope]). If the substatement in a selection-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 substatement. [..]
i.e. your code is really:
#include <iostream>
int main()
{
int b = 2;
if (int a = 0) {
}
else {
if (b == 2) {
int a;
}
}
}
Thus, the block you're looking at (the one introduced by the nested if
) is not the "outermost" block in question. So, though a
is in scope within that block, it can be shadowed.
This does mean you can't declare an a
inside a "naked" else
, i.e. the following is ill-formed:
#include <iostream>
int main()
{
int b = 2;
if (int a = 0) {
}
else {
int a;
}
}
/*
prog.cpp: In function ‘int main()’:
prog.cpp:9:9: error: redeclaration of ‘int a’
int a;
^
prog.cpp:6:11: note: ‘int a’ previously declared here
if (int a = 0) {
*/
The statement in stmt.stmt#stmt.pre-5 explicitly says:
[Note 2: A name introduced in a selection-statement or iteration-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 key term here is outermost block which is defined in stmt.block#1:
A compound statement (also known as a block) groups a sequence of statements into a single statement.
compound-statement:
{ statement-seq opt }
...
A compound statement defines a block scope.
So stmt.stmt#stmt.pre-5 is essentially saying:
if (int a = 0)
{ // outermost block
int a; // so ill-formed
}
but
if (int a = 0)
{ // outermost block
{ // inner block
int a; // so well-formed
}
}
The same rules apply in your example with the block introduced by the nested if
statement.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With