如何避免由于编译器错误而导致无法访问的代码警告

How to avoid an unreachable code warning due to a compiler bug?

本文关键字:访问 警告 代码 何避免 编译器 错误      更新时间:2023-10-16

VS2015更新2的可重现测试用例如下。我们尝试使用"警告级别 4"进行构建,我们将警告视为致命错误,以提高注意到所述警告的机会。我希望社区中的某个人已经遇到过这个问题,并找到了合理的解决方法。

如果没有其他人看到类似的问题,这可能被证明过于本地化,所以我想指出,潜在的问题是"一个人应该多严重地破坏代码库以避免糟糕的编译器警告",或者等效地,"一个人应该如何向丢失错误报告的编译器供应商报告错误"。

#ifdef _WIN32
#pragma warning( push )
#pragma warning( disable : 4702 ) // As suggested by comments
#endif
template <class Type>
void func (Type t)
{
    t.func ();
    t.func ();
}
#ifdef _WIN32
#pragma warning( pop )
#endif
struct NoThrow
{
    void func () {}
};
struct Throws
{
    void func () {throw 1;}
};
int main ()
{
    NoThrow nt;
    func (nt);
    Throws t;
    func (t);
}

这将触发无法访问的代码警告。模板化函数本身看起来很合理,但对于一个特定的实例化,编译器能够确定第二个 t.func() 已死,因此它会警告无法访问的代码。

对于VS2015来说,这似乎是一个相当明显的实现质量问题,所以我们在这里打开了一个错误报告。

我们得到了Microsoft的一些指导,

遗憾的是,编译器的后端(此警告的来源)没有将模板函数实例化作为单个模板函数实例的真正概念。它们都只是具有非常相似名称的函数,如果它曾经费心将(装饰的)名称相互比较的话。它永远不会这样做。因此,它在这里看到的是一个函数,其中包含一些无法访问的代码,它警告它,另一个函数没有无法访问的代码,它没有。您提出的"跨函数警告"概念,我们收集和比较不同模板机构的数据,并且仅在这样或那样时才发出警告,在纯 LTCG 二进制文件下非常困难,否则是不可能的。

考虑一个标题foo.h中的模板Foo。假设 a.cpp 包含它并创建具有无法访问代码的 Foo,然后 b.cpp 包含它并创建没有无法访问代码的 Foo。你建议在a.cpp Foo不应该警告,尽管无法访问的代码,因为Foo没有无法访问的代码。但是,Foo被编译在不同的文件中,在不同的过程中,在不同的cl.exe调用中,并且在将来最不方便。显然,编译器没有能力进入一个尚未诞生的过程,并提取计算是否应该发出警告所需的信息。

我们在这里唯一真正可行的选择是关闭模板无法访问的代码警告,老实说,在我们确定所做的伤害大于所做的好处之前,这不会发生(这是一个净坏)。警告有误报,它发生了。我会尝试考虑其他选项,并研究行号/文件的事情。

上面的链接可能不可用,但由于互联网带有缓存,您可以在此处查看副本或使用2744730和不正确的模板中无法访问的代码警告实例化找到自己的副本。

因此,如果我们假设底层模板实例化模型是消除函数的副本,然后对它们进行与其他任何函数相同的警告分析,那么我们如何避免死代码警告?我目前在向当前受影响的十几个模板添加标签调度或关闭全局警告之间左右为难。

编辑:直接链接似乎又上线了

我会

说这是正确的行为,尽管它可能很烦人。的实施者

template <class Type>
void func (Type t)
{
    t.func ();
    t.func ();
}

可能会对这个警告感到非常高兴。此外,编译器通常无法确定是否有会生成无效或有效代码的所有Type。因此,它会等到指定Type并继续,就像使用该固定类型输入代码一样。