为什么即使没有涉及签名的类型,std :: push_heap也会生成-Wstrict-overflow = 3警告?

问题描述

根据-Wstrict-overflow,第3级文档:

还警告其他简化比较的情况。例如:x + 1> 1简化为x> 0。

如果优化设置为-O2,但不低于3,则下面显示的MWE会在级别3和更高级别(但不低于 AND )上发出以下警告。 g ++版本9.3.0和10.2体现了这一点。

$ g ++ -O3 -Wall -Wextra -pedantic -std = c ++ 17 -Wstrict-overflow = 3 a.cpp
a.cpp:在函数‘void std :: push_heap(_RAIter,_RAIter)[带有_RAIter = long unsigned int *]的情况下”: a.cpp:8:1:警告:假设将X +-C1 cmp C2更改为X cmp C2-+ C1 [-Wstrict-overflow]时未发生有符号溢出

Live demo

MWE

#include <algorithm>

int main() {
  std::size_t v[] = {0,10,3};
  std::make_heap(std::begin(v),std::end(v));
  std::pop_heap(std::begin(v),std::end(v));
  std::push_heap(std::begin(v),std::end(v)); // <---
}

问题

  • 这是库实现中的错误吗?我什么都没有看到任何签名类型。
  • 如何在保持-Wstrict-overflow最高级别5的同时解决此问题?

解决方法

  • 这是库实现中的错误吗?我什么都看不到任何签名类型。

不。该库的实现是正确的。使用-fsanitize=undefined确认没有溢出。

警告仅告诉您编译器假定没有溢出发生。如果假定代码没有未定义的行为,则可以更积极地优化代码,因此可以假定代码没有溢出。警告只是告诉您进行了这样的假设,因为如果您向函数提供的输入实际上确实导致溢出,则该假设可能是错误的。

因此,警告表示“您最好不要在此处提供错误的输入,因为那样会使该优化产生不正确的结果”。

我已经报告了一个编译器错误(PR 96658),但严格来说,GCC的行为如所记录。

  • 如何在保持-Wstrict-overflow最高水平5的同时解决此问题?

-Wstrict-overflow的文档很明显会带来误报,因此不要将其与-Werror结合使用,这很愚蠢。