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