奇怪的结构&GCC&clang(void*返回类型)

Strange construct & destructor syntax in GCC & clang (void* return type)

本文关键字:amp void 返回类型 clang GCC 结构      更新时间:2023-10-16

在编写一些C++代码(使用clang、x86_64-linux进行编译(时,我意外地编写了以下构造:

class Class {
*Class() {}
};

即构造函数名称前面带有星号(*(。

我注意到你可以在前面加任意数量的*;它也适用于析构函数,即

class Class {
********Class() {}
********~Class() {}
};

Clang编译它时没有任何错误或警告。

但是GCC发出警告

控制到达非无效功能的末尾

这让我相信我实际上是在声明一个返回类型为void*(或void********(的构造函数/析构函数。编写任何类型的带有值的返回语句都会产生错误(正如预期的那样(:

return nullptr;
return {};
...

有趣的是,生成的LLVM IR位代码正确地包含一个void函数:

define void @_ZN5ClassC2Ev(%struct.Class* %this) {...}
define void @_ZN5ClassD2Ev(%struct.Class* %this) {...}

搜索有关此的任何信息都没有找到任何结果。所以我的问题是:这个标准是符合C++还是GCC&Clang?或者可能是一些兼容性功能?如果正确,它的用例是什么。

它看起来像一个bug。因为它不符合标准。声明或定义构造函数的标准方法是在[class.cctor]/1:中

构造函数没有名称。在构造函数的声明中声明符是形式的函数声明符

ptr声明符(参数声明子句(noexcept说明符opt属性说明符seqptit

其中ptr声明器仅由id表达式组成可选属性说明符seq和可选环绕括号,id表达式具有以下形式之一:

  • 在属于类的成员规范但不是友元声明的成员声明中,id表达式是直接封闭类的注入类名
  • 在属于类模板的成员规范但不是友元声明的成员声明中,id表达式为一个类名,用于命名立即封闭类模板;或
  • 在命名空间范围的声明或友元声明中,id表达式是命名构造函数的限定id([class.qual](

类名不能是typedef名称。在构造函数中声明,可选decl说明符seq中的每个decl说明符应为friend、inline、explicit或constexpr。

正如您在我强调的部分中看到的,ptr-declarator必须只是一个id表达式。或者用更简单、稍微不那么准确的术语来说,它必须只是类名。

那么,为什么可以在Clang和GCC中添加星号呢?他们似乎有一个bug,并且没有在这里对ptr-declarator应用语义约束。这些约束很重要,因为纯语法确实允许使用星号。它在[dcl.dell]/4中(仅部分复制(:

声明器具有语法

ptr声明符:noptr声明器ptr运算符ptr声明符ptr运算符:*属性说明符seqoptcv限定符seqopt&属性说明符seqopt&属性说明符seq选项嵌套名称说明符*属性说明符seq-选择cv限定词seqopt

看到ptr-operator位的语法了吗?它说*可以出现在你放它的地方。或者&甚至&&。但我首先引用的声明中的语义使其成为非法。

因此,人们必须得出结论,这是GCC和Clang中的一个错误。