Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The variable redeclared in the outermost block of a substatement

#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?

like image 993
xmh0511 Avatar asked Nov 06 '20 01:11

xmh0511


2 Answers

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 the else form of the if 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) {
*/
like image 157
Asteroids With Wings Avatar answered Oct 23 '22 09:10

Asteroids With Wings


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.

like image 44
cigien Avatar answered Oct 23 '22 10:10

cigien