对于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来说,这似乎是一个相当明确的实施问题,因此我们开了一个错误报告here。
我们收到了微软的一些指导,
不幸的是,编译器的后端(此警告源自此处)没有模板函数实例化的真实概念作为单个模板函数的实例。它们都只是具有非常相似的名字的函数,如果它曾经打算将(装饰的)名称与彼此进行比较。它永远不会。所以它在这里看到的是一个函数,它有一些无法访问的代码,它警告它,另一个函数没有无法访问的代码,它没有。您提出的这种“交叉功能警告”的概念,我们收集并比较不同模板实例中的数据,并且仅在纯LTCG二进制文件的情况下警告这个或那个是非常困难的,否则是不可能的。
在标题foo.h中考虑模板Foo。假设a.cpp包含它并创建具有无法访问代码的Foo,然后b.cpp包含它并创建没有无法访问代码的Foo。你建议在a.cpp中Foo不应该警告,调用无法访问的代码,因为Foo存在没有无法访问的代码。但是,Foo是在不同的文件中,在不同的进程中,在不同的cl.exe调用中编译的,并且在将来最不方便。很明显,编译器没有能力将未来的过程扩展到未出生的过程,并提供计算是否需要警告所需的信息。
我们这里唯一真正可行的选择是关闭所有模板的无法访问代码警告,我会说实话,直到我们确定所造成的伤害大于完成的好处才会发生(这是一个坏的坏)。警告有误报,它会发生。我将尝试考虑其他选项,并查看行号/文件。
以上链接可能无法使用,但随着互联网附带缓存,您可以看到副本here或使用2744730和错误 - 不可达 - 代码 - 警告 - 模板 - 实例化找到您自己的副本。
因此,如果我们假设底层模板实例化模型是要删除函数副本,然后对它们进行相同的警告分析,那么我们如何才能避免死代码警告呢?我目前在将标签调度添加到当前受影响的十几个模板或全局关闭警告之间徘徊。
编辑:直接链接似乎再次生效
答案 0 :(得分:2)
我会说这是正确的行为,尽管很烦人。
的实施者template <class Type>
void func (Type t)
{
t.func ();
t.func ();
}
对此警告感到非常高兴。此外,编译器通常不可能解决是否存在会产生无效或有效代码的全部Type
。因此,它会等到Type
被指定并继续,就像使用该固定类型输入代码一样。