错误:声明为“noreturn”的函数不应该返回

4

在我的工作场所,我们使用不同的内部名称来表示noreturn属性。假设它是INTERNAL_DONT_RETURN

我正在编写一个类的成员函数,在其中我进行了如下操作:

INTERNAL_DONT_RETURN void foo() const
{
    if(!*this)
    {
       throw CoolException();
    }
    m_call_throw();
}

这个m_call_throw()是一个私有类成员std::function<void()>m_call_throw,在类的构造函数中作为lambda表达式被填充。这个lambda什么也不做,只是执行以下代码: m_call_throw([uncoolID]() { throw UncoolException(uncoolID); }) 现在,gcc-4.9.3和clang都给我以下警告: error: function declared 'noreturn' should not return [-Werror,-Winvalid-noreturn] } ^ 我已经查阅了这个问题这个问题,但它们都没有解释以上警告的原因。
1)编译器是否像这里所解释的那样隐式添加了return
2)即使我抛出异常,为什么编译器认为我的函数会返回?
3)noreturn属性提到:

noreturn关键字不影响异常路径:标记为noreturn的函数仍然可以通过抛出异常或调用longjmp返回给调用者。

这与我的问题有关吗?

请提供一个 [MCVE]。 - m.s.
3个回答

9
但是你确实会返回!如果if语句为假,你会通过函数结尾的落下来返回。你可能知道这永远不会发生,因为m_call_throw()也从未返回过(是吧?),但编译器显然并不理解这种逻辑。 m_call_throw()被标记为noreturn了吗?如果没有,请添加。如果编译器无法识别,您可以在函数末尾添加另一个throw,您知道它永远不会被执行,但应该可以消除警告。

2
编译器无法证明该函数一定会抛出异常。这不是一个错误 - 总会有编译器无法证明的情况。是否应该警告您是一个有趣的问题。警告您意味着它有时会报告不存在的错误; 不警告您意味着它有时会漏掉真正的错误。您可以轻松地使警告变为非致命性,或通过多种方式消除它。为此特定文件禁用它,或在末尾添加一个调用abort的语句。每种情况都需要做出权衡,但这就是生活。如果您可以从lambda/std::function切换到普通成员函数,请这样做,并将其设置为noreturn。遗憾的是,您无法拥有noreturn函数类型、noreturnstd::functionnoreturn lambda,这在我看来是语言中的一个错误。

+1,因为我们目前还不能拥有noreturn函数类型、noreturn std::function或noreturn lambda。 - Recker

0
那是因为你的foo返回了,或者至少看起来像是返回了。
当使用noreturn声明函数时,该函数必须不返回:
void Foo() __attribute__((noreturn));

void Foo()
{
    // The application will exit, without returning.
    exit(0);
}

int main()
{
    Foo();
}

你知道你的 m_call_throw 也不会返回,但编译器并不知道。

因此,明确告诉编译器它不会返回可能会有所帮助,如下所示:

void Foo() __attribute__((noreturn));
void m_call_throw() __attribute__((noreturn));

void Foo()
{
    // Ok, no return huh?
    m_call_throw();
}

现场演示在这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接