GCC 11.x vexing-parse + 不一致的错误(重新声明为不同的符号类型),这是 GCC 错误吗?
GCC 11.x vexing-parse + inconsistent error (redeclaration as different symbol type), is it a GCC bug?
下面的代码编译没有问题from GCC 4.7.1 up to but not including GCC 11.1:
constexpr int SomeValue = 0;
void test () {
void (SomeValue) ();
}
在 GCC 11.x 上它失败了:
<source>:4:23: error: 'void SomeValue()' redeclared as different kind of entity
4 | void (SomeValue) ();
| ^
<source>:1:15: note: previous declaration 'constexpr const int SomeValue'
1 | constexpr int SomeValue = 0;
| ^~~~~~~~~
但是“重新声明为不同类型的实体”这个错误对我来说似乎很奇怪:撇开不明确的解析可能性不谈,范围是不同的。此外,这些测试都在 all versions of GCC since 4.7.1 (including 11.x) 上编译,尽管据我所知每个测试都将 SomeValue
重新声明为“不同类型的实体”:
constexpr int SomeValue = 0;
void test1 () { typedef void (SomeValue) (); }
void test2 () { double SomeValue; }
void test3 () { using SomeValue = char *; }
void test4 () { void (* SomeValue) (); }
void test5 () { struct SomeValue { }; }
void test6 () { enum class SomeValue { }; }
作为一个相对不那么荒谬的例子,这段代码也以类似的方式失败了 from 11.x on:
constexpr int SomeValue = 0;
struct SomeClass {
explicit SomeClass (int) { }
void operator () () { }
};
void test () {
SomeClass(SomeValue)();
}
虽然在这种情况下,它前面有一个令人烦恼的解析警告,但在 11.x 之前也不存在(警告在这里但不在上面的事实是有道理的,警告的事实没有出现前11.x是有趣的一点):
<source>: In function 'void test()':
<source>:9:25: warning: empty parentheses were disambiguated as a function declaration [-Wvexing-parse]
9 | SomeClass(SomeValue)();
| ^~
<source>: At global scope:
<source>:9:26: error: 'SomeClass SomeValue()' redeclared as different kind of entity
9 | SomeClass(SomeValue)();
| ^
<source>:1:15: note: previous declaration 'constexpr const int SomeValue'
1 | constexpr int SomeValue = 0;
| ^~~~~~~~~
Compiler returned: 1
但是等等!还有更多!
这段代码——由于与上面相同的解析歧义,我预计它会在 11.x 上失败——在 all those versions of GCC (including 11.x):
上编译得很好
constexpr int SomeValue = 0;
auto closure = [] (int) {
return [] () { };
};
void test () {
closure(SomeValue)(); // <-- doesn't cause any problems
}
那里没有警告或任何东西。
所以...这是怎么回事?为什么在那些特定情况下 SomeValue
被“重新声明为不同类型的实体”只是一个问题,而且只是从 GCC 11.1 开始,为什么 closure(SomeValue)()
没有遇到与 SomeClass(SomeValue)()
?
还有什么变化? GCC在这里正确吗?它是 GCC 11.x 中引入的新错误吗?或者也许是最终在 11.x 中修复的旧错误?或者根本不是一个错误,还有其他改变?
我正在努力想出一个一致的解释。
区别在于您的第一个代码段声明了一个全局存在的函数;您所有其他声明都是本地实体。
(请注意,即使声明有效,您也无法调用该函数,因为它不存在。)
在最后一个片段中,closure
不是类型,因此不能是声明。
下面的代码编译没有问题from GCC 4.7.1 up to but not including GCC 11.1:
constexpr int SomeValue = 0;
void test () {
void (SomeValue) ();
}
在 GCC 11.x 上它失败了:
<source>:4:23: error: 'void SomeValue()' redeclared as different kind of entity
4 | void (SomeValue) ();
| ^
<source>:1:15: note: previous declaration 'constexpr const int SomeValue'
1 | constexpr int SomeValue = 0;
| ^~~~~~~~~
但是“重新声明为不同类型的实体”这个错误对我来说似乎很奇怪:撇开不明确的解析可能性不谈,范围是不同的。此外,这些测试都在 all versions of GCC since 4.7.1 (including 11.x) 上编译,尽管据我所知每个测试都将 SomeValue
重新声明为“不同类型的实体”:
constexpr int SomeValue = 0;
void test1 () { typedef void (SomeValue) (); }
void test2 () { double SomeValue; }
void test3 () { using SomeValue = char *; }
void test4 () { void (* SomeValue) (); }
void test5 () { struct SomeValue { }; }
void test6 () { enum class SomeValue { }; }
作为一个相对不那么荒谬的例子,这段代码也以类似的方式失败了 from 11.x on:
constexpr int SomeValue = 0;
struct SomeClass {
explicit SomeClass (int) { }
void operator () () { }
};
void test () {
SomeClass(SomeValue)();
}
虽然在这种情况下,它前面有一个令人烦恼的解析警告,但在 11.x 之前也不存在(警告在这里但不在上面的事实是有道理的,警告的事实没有出现前11.x是有趣的一点):
<source>: In function 'void test()':
<source>:9:25: warning: empty parentheses were disambiguated as a function declaration [-Wvexing-parse]
9 | SomeClass(SomeValue)();
| ^~
<source>: At global scope:
<source>:9:26: error: 'SomeClass SomeValue()' redeclared as different kind of entity
9 | SomeClass(SomeValue)();
| ^
<source>:1:15: note: previous declaration 'constexpr const int SomeValue'
1 | constexpr int SomeValue = 0;
| ^~~~~~~~~
Compiler returned: 1
但是等等!还有更多!
这段代码——由于与上面相同的解析歧义,我预计它会在 11.x 上失败——在 all those versions of GCC (including 11.x):
上编译得很好constexpr int SomeValue = 0;
auto closure = [] (int) {
return [] () { };
};
void test () {
closure(SomeValue)(); // <-- doesn't cause any problems
}
那里没有警告或任何东西。
所以...这是怎么回事?为什么在那些特定情况下 SomeValue
被“重新声明为不同类型的实体”只是一个问题,而且只是从 GCC 11.1 开始,为什么 closure(SomeValue)()
没有遇到与 SomeClass(SomeValue)()
?
还有什么变化? GCC在这里正确吗?它是 GCC 11.x 中引入的新错误吗?或者也许是最终在 11.x 中修复的旧错误?或者根本不是一个错误,还有其他改变?
我正在努力想出一个一致的解释。
区别在于您的第一个代码段声明了一个全局存在的函数;您所有其他声明都是本地实体。
(请注意,即使声明有效,您也无法调用该函数,因为它不存在。)
在最后一个片段中,closure
不是类型,因此不能是声明。