【问题标题】:g++ [[noreturn]] on a virtual methodg++ [[noreturn]] 在虚方法上
【发布时间】:2020-03-11 22:51:26
【问题描述】:

我在尝试清理 g++ 编译器警告时遇到了一些麻烦。

假设我有这门课:

class A
{
public:
    [[noreturn]] virtual void will_throw() { throw 0; }
};

在一个非 void 函数中,我调用 will_throw 而不返回。

如果我按价值这样做,即:

int g()
{
    A a;
    a.will_throw();
}

然后我没有收到-Wreturn-type 警告。

如果我用指针来做:

int g()
{
    A a;
    A* aptr = &a;
    aptr->will_throw();
}

然后我得到“警告:在返回非 void [-Wreturn-type] 的函数中没有返回语句”

如果我从A::will_throw 的声明中删除virtual,那么在指针上调用它也不会产生任何警告。如果方法是纯虚拟的,则在引用上调用该方法似乎会产生警告,否则不会。

我找不到任何说明它应该如何工作的东西,而且这些情况都不会在 Clang 中产生警告。这是 GCC 中的错误吗?

【问题讨论】:

  • 对我来说当然是一个错误。我能够使用 GCC 9 重现此问题,而 Clang 9 似乎没有任何问题。

标签: c++ c++11 g++


【解决方案1】:

由于函数是虚函数,编译器不知道(不跟踪分配)通过指针(或引用)调用的是A::will_throw,而不是一些可能不是noreturn 的覆盖函数。由于这只是一个警告,因此两种行为(或从不警告,或始终警告!)都符合要求。

【讨论】:

  • 这对我来说似乎违反直觉。虚函数本身具有noreturn 属性,我应该认为就编译器而言,这是一个足够的承诺,即覆盖不会返回。我知道属性对继承的含义存在一些歧义,但我不知道任何其他方式来指定此意图。如果 GCC 的当前行为并非完全不正确,我仍然认为它可以改进。
  • @squeevee:鉴于 [[noreturn]] 函数实际返回是未定义的行为,将其传播给覆盖器似乎相当激烈(同时具有严格的表达能力:也许你的意思是基本实现永远不会被使用并将误用报告为例外)。
  • 我不确定我是否完全理解您的意思。问题不在于可执行文件的行为(或昂贵),在实际实践中也不需要在运行时通过错误检查来强制执行此意图。一切正常。但是编译器的警告表明它误解了我认为相当明确的意图。
  • @squeevee:我的观点是,标准并没有说 [[nodiscard]] 是继承的(有合理的理由),这似乎是 GCC 以这种方式对待它的一个很好的理由,即使是咨询诊断.
猜你喜欢
  • 2015-12-15
  • 2018-12-05
  • 1970-01-01
  • 2011-09-30
  • 2012-05-19
  • 2020-10-24
  • 2019-09-08
  • 2015-06-21
  • 2018-10-20
相关资源
最近更新 更多