错误:声明'noreturn'不应返回的函数

error: function declared 'noreturn' should not return

本文关键字:返回 函数 错误 noreturn 声明      更新时间:2023-10-16

在我的工作场所,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属性提到

当applies:noreturn标记的函数仍然可以通过抛出异常或调用longjmp。

这与我的问题有关吗?

但是你回来了!如果if语句为false,则通过函数末尾的下降返回。您可能知道这种情况永远不会发生,因为m_call_throw()也不会返回(是吗?),但编译器显然不理解这种逻辑。

m_call_throw()是否标记为noreturn?如果没有,就添加它。如果编译器没有注意到这一点,你可以在函数的末尾添加一个额外的抛出,你知道这个抛出永远不会到达,但应该会使警告静音。

编译器无法证明函数将始终抛出。这不是一个错误——编译器总是会在某些情况下无法证明这两种情况。

它是否应该警告你是一个有趣的问题。警告意味着它有时会报告不存在的错误;没有警告意味着它有时会错过一个真正的bug。

您可以很容易地使警告不致命,或者通过多种方式使其静音。对此特定文件禁用它,或者在末尾添加对abort的调用。每种情况都需要权衡,但这就是生活。

如果您可以从lambda/std::函数切换到普通成员函数,只需这样做,并使其成为noreturn。遗憾的是,不能有noreturn函数类型、noreturnstd::functionnoreturnlambda,这是IMHO语言中的一个错误。

这是因为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();
}

现场演示在这里。