clang 说对 void consteval 函数的调用不是常量表达式

clang says call to void consteval function is not a constant expression

clang(trunk) 给出以下代码的错误:

consteval void f() {}

int main() 
{ 
    f();  // error: call to consteval function 'f' is not a constant expression
          // note: subobject of type 'void' is not initialized
}

而 gcc(trunk) 编译时没有错误。

我觉得这可能是一个 clang 错误,因为 gcc 和 clang 都接受这个代码:

consteval int g() { return 42; }

int main() 
{ 
    g();  // ok
}

这是 code 可以玩的。

这是 clang 错误,还是代码格式不正确,或者有 ub,还是其他什么?


编辑:我觉得有必要指出 clang 允许从其他函数调用 f,如果它们也是 consteval。它仅在从非 consteval 函数调用 f 时给出错误:

consteval int h() 
{ 
    f();       // ok
    return 42; 
}

demo.

我发现c++20 final draft的是:

9.2.5 The constexpr and constevals pecifiers[dcl.constexpr] (2) A constexpr or consteval specifier used in the declaration of a function declares that function to be a constexpr function. A function or constructor declared with the consteval specifier is called animmediate function. A destructor, an allocation function, or a deallocation function shall not be declared with the consteval specifier.

(3) The definition of a constexpr function shall satisfy the following requirements:

3.1 its return type (if any) shall be a literal type;

6.8 Types [basic.types]

(10) A type is a literal type if it is :

(10.1) cv void

...

因为此 voidconsteval 函数的有效 return 类型。

这是版本 10 和版本 11 之间以及上个月 fixed 之间引入的 Clang 错误。 consteval 在 Clang 中的实现大部分(但不完全)是完整的,这个错误是在其中一个补丁添加了更完整的 consteval 支持之后出现的。

细节:Clang 常量计算器的 top-level 入口点检查结果是否是常量表达式的允许结果——它检查结果是否不包含指向自动存储持续时间或临时变量的指针或类似的。但是此检查从未更新以适应 void 是文字类型,并且会拒绝 void 类型的值作为“未初始化”。在添加 consteval 支持之前从未注意到这一点,因为所有 top-level 常量评估都是非 void 类型。