是类型(::x);有效的?

虽然讨论Type(identifier); 语法以及它是如何声明的,我遇到了 Type(::x); 不适用于 Clang.我希望给定一个全局变量 x,它会将 ::x 视为一个表达式(::x + 2 有效)并强制转换::xType.但是,它会导致编译器错误.

这是一个简短的例子:

int x;int main() {int(::x);//不编译int(::x + 2);//编译}

Clang 3.5 给出的编译器错误是:

<块引用>

错误:'x' 的定义或重新声明不能命名全局作用域

然而,GCC 4.9.0 编译得很好.此代码是否有效?

解决方案

据我所知,draft C++ 标准 部分 8.3 声明符的含义 段落 6 上面写着(强调我的未来):

<块引用>

在声明 T D 中,其中 D 具有以下形式

( D1 )

包含的declarator-id的类型与中包含的declarator-id的类型相同声明

T D1

括号不会改变嵌入的声明符ID的类型,但它们可以改变复杂的绑定声明符.

所以:

int(::x);

相当于:

int ::x ;

这显然是无效的,这也会产生同样的错误.所以 gcc 4.9 在这里是不正确的,但由于这在稍后发布的 gcc 4.8.3 中看起来是固定的,我希望这会在 的后续版本中得到修复4.9 也是如此.尽管我在 gcc 4.8.3 错误修复列表,但他们并没有声称这是一个完整的列表.

第二种情况是函数式显式类型转换,在5.2.3 部分有介绍 显式类型转换(函数式表示法) 内容如下:

<块引用>

简单类型说明符 (7.1.6.2) 或类型名称说明符 (14.6)后跟一个带括号的表达式列表构造一个值给定表达式列表的指定类型.如果表达式列表是一个单个表达式,类型转换表达式等价(在定义,如果在含义中定义)到相应的演员表表达式 (5.4).[...]

这是明确的,因为::x + 2 是一个表达式.

当一个语句被认为是声明或表达式的部分是6.8 歧义解决,它说:

<块引用>

涉及表达式语句的语法存在歧义和声明:具有函数风格的表达式语句显式类型转换 (5.2.3) 作为其最左边的子表达式可以是与第一个声明符开始的声明没有区别带有 (. 在这些情况下,该语句是一个声明. [ 注意:要消除歧义,可能需要检查整个陈述确定它是表达式语句还是声明.这消除了许多例子的歧义.

并提供以下示例:

<块引用>

T(a)->m = 7;//表达式语句T(a)++;//表达式语句T(a,5)<<c;//表达式语句T(*d)(int);//宣言T(e)[5];//宣言T(f) = { 1, 2 };//宣言T(*g)(双(3));//宣言

注意:没有 () 那么 T ::DT 是一个类,它包含在5.1主要表达式的语法中.

更新

提交了 gcc 错误报告.

gcc 的回应是:

<块引用>

当前的 G++ 和 EDG 都将其视为有效表达式 (int)::x

由于此回复暗示 clang 不正确(我不同意),我提交了一个 clang 错误报告 和 较旧的错误报告 看起来很相似,似乎不同意 gcc 响应.

更新 2

为了回应 clang 错误报告,Richard Smith 同意这应该被视为声明并说:

<块引用>

这并不意味着 clang 是不正确的;事实上,Clang 是正确的在这里,据我所知.(我还向 EDG 发送了错误报告.)

也就是说,我们应该给出一个正确的'你遇到了一个令人烦恼的解析,这就是方法在这种情况下消除'错误.

更新 3

gcc 确认是个bug.

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.

相关文章