Is Type(::x); valid?

2019-01-17 15:23发布

问题:

While discussing the Type(identifier); syntax and how it's a declaration, I came across Type(::x); not working with Clang. I would expect that given a global variable x, it would treat ::x as an expression (::x + 2 works) and cast ::x to Type. However, it gives a compiler error.

Here is a short example:

int x;

int main() {
    int(::x); //does not compile
    int(::x + 2); //compiles
}

The compiler error given by Clang 3.5 is:

error: definition or redeclaration of 'x' cannot name the global scope

GCC 4.9.0, however, compiles this just fine. Is this code valid or not?

回答1:

As far as I can tell this is covered by draft C++ standard section 8.3 Meaning of declarators paragraph 6 which says (emphasis mine going forward):

In a declaration T D where D has the form

( D1 )

the type of the contained declarator-id is the same as that of the contained declarator-id in the declaration

T D1

Parentheses do not alter the type of the embedded declarator-id, but they can alter the binding of complex declarators.

so:

int(::x);

is equivalent to:

int ::x ;

which is clearly not valid, and this produces the same error as well. So gcc 4.9 is not correct here but since this looks fixed in the gcc 4.8.3 which was released later I would expect this to be fixed in later releases of 4.9 as well. Although I don't see any obvious matches for this issue in the gcc 4.8.3 bugs fixed list but they don't claim it is a complete list.

The second case is a functional explicit type conversion which is covered in section 5.2.3 Explicit type conversion (functional notation) which says:

A simple-type-specifier (7.1.6.2) or typename-specifier (14.6) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4).[...]

This is unambiguous since ::x + 2 is an expression.

The section that covers when a statement is considered a declaration or a expression is 6.8 Ambiguity resolution which says:

There is an ambiguity in the grammar involving expression-statements and declarations: An expressionstatement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration. [ Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. This disambiguates many examples.

and provides the following examples:

T(a)->m = 7; // expression-statement
T(a)++; // expression-statement
T(a,5)<<c; // expression-statement
T(*d)(int); // declaration
T(e)[5]; // declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration

Note: without the () then T ::D is a qualified-id in the case of T being a class, that is a covered in the grammar of 5.1 Primary expressions.

Update

Filed a gcc bug report.

gcc's response is that:

Current G++ and EDG both treat it as the valid expression (int)::x

Since this response implies clang is incorrect(I don't agree though), I filed a clang bug report and older bug report looks similar and seems to disagree with the gcc response.

Update 2

In response to the clang bug report Richard Smith agrees this should be treated as a declaration and says:

That does not imply clang is incorrect; in fact, Clang is correct here, as far as I can see. (I've also sent a bug report to EDG.)

That said, we should give a proper 'you hit a vexing parse, here's how to disambiguate' error in this case.

Update 3

gcc confirms it is a bug.



回答2:

This looks like the most vexing parse to me. If it can be parsed as a declaration it will be. The first could be parsed as a declaration of an int variable (int ::x;), but the :: is illegal in that context. The second has to be an expression and so the compiler does the math, casts it to int, and throws away the result.

Was this a pedantic question, or is there another problem as well? If you have a specific problem you're trying to solve, additional information would allow a workaround for your use case.