是否存在编译器无法诊断丢失返回的情况?

for*_*818 5 c++ return compiler-warnings

我做了一些研究,以找出为什么丢失的返回不能是错误,而是未定义的行为。我在一个错误报告中发现了这个评论,该报告使用以下示例来说明为什么它不能是错误:

   template<typename T>
   T maybe_call(std::function<T(void)> f) {
           if (f)
                   return f();
           else
                   abort_program();

           // Cannot write a return here, because we have no way to create a value of t
   }
Run Code Online (Sandbox Code Playgroud)

请注意,此示例是完全有效的代码。它在所有分支上都没有回报,但仍然没有UB。这解释了为什么没有在所有分支上返回是 UB,而不是错误。这个例子可以被“固定”申报abort_program();[[noreturn]]使之成为反驳的少。我怀疑编译器在正确诊断此示例时会遇到问题。如果缺少一个返回会变成一个错误,规则可能要改变一点,因为只有通过[[noreturn]]上面的例子才能正确诊断。

但是,我正在寻找的是一个不同的示例,其中编译器无法检测到丢失的返回。该评论还提到存在编译器无法诊断的案例,但我找不到这样的例子。

如果警告是可靠的(误报,如上面的那个除外),我可以将警告视为错误以安全起见。

真的有编译器无法检测到丢失返回的情况吗?是仅在病态代码中,还是在日常代码中也会发生?我可以依赖警告吗?

为了让它有责任感,让我们专注于 gcc(最新版本):在什么情况下 gcc 无法警告丢失的返回?

for*_*818 1

很难证明某些东西不存在,但是很难找到一个示例,这足以令人信服地看出,只有病态的代码才会导致编译器不会警告丢失的返回。

首先,我的思路是构建一个复杂的示例:

int fun() {
    goto exit;
    return 1;
    exit: ;      
}
Run Code Online (Sandbox Code Playgroud)

然而,无论我如何努力,gcc 都会对此类代码发出警告。我想得越多,我就越确信问题不在于编译器不会发出警告的代码,而在于错误的提示。如果问题中的例子改为

   template<typename T>
   T maybe_call(std::function<T(void)> f) {
           if (f)
                   return f();
           else
                   maybe_abort_program();

           // Cannot write a return here, because we have no way to create a value of t
   }
Run Code Online (Sandbox Code Playgroud)

然后由编译器决定maybe_abort_program最终是否返回,这就是暂停问题,不能在所有情况下都决定。更改函数的名称当然不会改变任何内容,但这只是为了强调,即使认为该函数可以标记为[[noreturn]],但不将其标记为这样,代码仍然有效(或无效),并且编译器无法可靠地诊断这一点。

但是,编译器可以对此类情况发出警告。经过一番尝试后,我没有找到任何编译器不发出警告的示例。因此我的结论是:我可以(在某种程度上)依赖这个警告。