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 不是类型,因此不能是声明。