Why is variable declared in an if-statement still in scope in else block?

Viewed 338

Consider this code:

if (int* p = nullptr) {
}
else {
    std::cout << *p << std::endl;
}

This compiles with clang 7.0.1 with -std=c++17, -Wall, -Wextra and -pedantic-errors without a single warning generated.

I've got two questions:

  1. How is this possible? I always thought that scope of such variables ends with the if-block. I'd be thankful for quotation from the standard if possible.

  2. If it's legal though, shouldn't it at least generate a warning? Are there any reasonable applications of such feature?

1 Answers

Why is variable declared in an if-statement still in scope in else block?

Because the standard says that it is. It was designed so presumably because it is useful.

  1. How is this possible?

It's unclear why it wouldn't be possible.

I always thought that scope of such variables ends with the if-block.

You assumed wrongly.

I'd be thankful for quotation from the standard if possible. [language-lawyer]

Latest draft says:

[stmt.select.general]

Selection statements choose one of several flows of control. selection-statement:

  • ...
  • if constexpropt ( init-statementopt condition ) statement else statement
  • ...

Note that the entire if (condition) statement else statement is a selection-statement.

[basic.scope.block]

Each

  • selection or iteration statement ([stmt.select], [stmt.iter]),
  • ...

introduces a block scope that includes that statement or handler.

Note that the condition is directly within the if-statement and not inside a sub-statement, and thus a declaration within it extends until the end of the entire block scope, which contains both the if-sub-statement, and the else-sub-statement (not standard names for those sub-statements).

There is also a pretty clear example that demonstrates ill-formed re-declarations, and incidentally shows the scope of such declaration:

if (int x = f()) {
  int x;            // error: redeclaration of x
}
else {
  int x;            // error: redeclaration of x
}

  1. If it's legal though, shouldn't it at least generate a warning?

Yeah, it would be nice if compilers were able to detect all provable null pointer indirections at compile time. It may be worth submitting a feature request regarding this corner case.

Are there any reasonable applications of such feature?

Sure. Following fabricated example seems reasonable to me:

if (Response r = do_request()) {
    log << "great success. content: " << r.content;
} else {
    log << "someone broke it :( error: " << r.error_code;
}

Or if you dislike implicit conversions:

if (Response r = do_request(); r.is_success()) {
Related