【问题标题】:Why does std::push_heap generate a -Wstrict-overflow=3 warning even if no signed types are involved?为什么即使不涉及签名类型,std::push_heap 也会生成 -Wstrict-overflow=3 警告?
【发布时间】:2020-12-03 21:55:55
【问题描述】:

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

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

如果优化设置为-O2 及以上但不低于以下,则下面显示的 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) [with _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 的同时解决此问题?

【问题讨论】:

  • 签名类型是 usedstd::__push_heap 用于索引:while (__holeIndex &gt; __topIndex &amp;&amp; ...)。如果从std::__push_heap 中删除此比较,则警告将消失。
  • 库中没有错误。编译器告诉您它假定没有整数溢出,而不是实际上存在溢出。用-fsanitize=undefined编译显示运行时没有溢出。
  • @JonathanWakely 如果只是提到这是一个假设,这不应该是“信息”级别的诊断吗?由于这是作为警告诊断发出的,it fails with -Werror,这似乎是不可取的。
  • @Human-Compiler 这也是我的评估。标准库不应发出警告。任何警告。除非它们源自用户代码,在这种情况下我认为它们不会这样做。
  • 文档很清楚:“因此,这个警告很容易给出误报:关于实际上不是问题的代码的警告。”将此警告与-Werror 结合起来有点傻。你得到你想要的。

标签: c++ g++ warnings c++-standard-library signed-overflow


【解决方案1】:
  • 这是库实现中的错误吗?我没有看到任何签名类型。

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

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

所以警告的意思是“你最好不要在这里提供错误的输入,因为那会使这个优化产生不正确的结果”。

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

  • 如何在将 -Wstrict-overflow 保持在其最高级别 5 的同时解决此问题?

-Wstrict-overflow 的文档很清楚会给出误报,所以不要将它与 -Werror 结合起来,这很愚蠢。

【讨论】:

    猜你喜欢
    • 2021-08-06
    • 2012-02-18
    • 2017-06-24
    • 2021-06-13
    • 1970-01-01
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    相关资源
    最近更新 更多