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