为什么即使不涉及签名类型,std::push_heap 也会生成 -Wstrict-overflow=3 警告?
Why does std::push_heap generate a -Wstrict-overflow=3 warning even if no signed types are involved?
根据 -Wstrict-overflow
的文档,级别 3:
Also warn[s] about other cases where a comparison is simplified. For example: x + 1 > 1 is simplified to x > 0.
如果优化设置为 -O2
及以上但不低于 AND,则下面显示的 MWE 将在级别 3 及以上但不低于以下警告。 g++ 版本 9.3.0 和 10.2 展示了这一点。
$ g++ -O3 -Wall -Wextra -pedantic -std=c++17 -Wstrict-overflow=3 a.cpp
a.cpp: In function ‘void std::push_heap(_RAIter, _RAIter) [with _RAIter = long unsigned int*]’:
a.cpp:8:1: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C2 -+ C1 [-Wstrict-overflow]
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 的同时解决这个问题?
- Is this a bug in the library implementation? I don't see any signed types whatsoever.
没有。库实现是正确的。使用 -fsanitize=undefined
确认没有溢出。
该警告仅告诉您编译器假设没有发生溢出。如果它假设代码没有未定义的行为,它可以更积极地优化代码,因此它假设代码没有溢出。该警告只是告诉您做出了这样的假设,因为如果您向实际导致溢出的函数提供输入,则该假设可能是错误的。
所以警告的意思是“你最好不要在此处提供错误的输入,因为这会使此优化产生不正确的结果”。
我报告了一个编译器错误 (PR 96658),但严格来说 GCC 的行为与记录的一致。
- How can I fix this while still keeping -Wstrict-overflow at its max level 5?
-Wstrict-overflow
的文档很清楚,它给出了误报,所以不要将它与 -Werror
结合使用,那是愚蠢的。
根据 -Wstrict-overflow
的文档,级别 3:
Also warn[s] about other cases where a comparison is simplified. For example: x + 1 > 1 is simplified to x > 0.
如果优化设置为 -O2
及以上但不低于 AND,则下面显示的 MWE 将在级别 3 及以上但不低于以下警告。 g++ 版本 9.3.0 和 10.2 展示了这一点。
$ g++ -O3 -Wall -Wextra -pedantic -std=c++17 -Wstrict-overflow=3 a.cpp
a.cpp: In function ‘void std::push_heap(_RAIter, _RAIter) [with _RAIter = long unsigned int*]’: a.cpp:8:1: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C2 -+ C1 [-Wstrict-overflow]
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 的同时解决这个问题?
- Is this a bug in the library implementation? I don't see any signed types whatsoever.
没有。库实现是正确的。使用 -fsanitize=undefined
确认没有溢出。
该警告仅告诉您编译器假设没有发生溢出。如果它假设代码没有未定义的行为,它可以更积极地优化代码,因此它假设代码没有溢出。该警告只是告诉您做出了这样的假设,因为如果您向实际导致溢出的函数提供输入,则该假设可能是错误的。
所以警告的意思是“你最好不要在此处提供错误的输入,因为这会使此优化产生不正确的结果”。
我报告了一个编译器错误 (PR 96658),但严格来说 GCC 的行为与记录的一致。
- How can I fix this while still keeping -Wstrict-overflow at its max level 5?
-Wstrict-overflow
的文档很清楚,它给出了误报,所以不要将它与 -Werror
结合使用,那是愚蠢的。