为什么GCC -O3与std :: deque上的过滤器迭代器导致无限的std :: distance?

Dan*_*iel 37 c++ gcc deque filter-iterator c++11

在经历了许多痛苦和痛苦之后,我已经找到了一些非常奇怪的行为,std::distance当给出一系列boost::filter_iterators超过a 时,它永远不会返回std::deque.看来问题是GCC(6.1+)的-O3优化问题.这是一个演示违规行为的示例:

#include <string>
#include <deque>
#include <iterator>
#include <iostream>

#include <boost/iterator/filter_iterator.hpp>

struct Foo
{
    std::string bar, s = "";
    char a = '\0';
};

int main()
{
    const std::deque<Foo> foos(14, {""});
    const std::string test {};
    const auto p = [test] (const auto& foo) { return foo.bar == test; };
    using boost::make_filter_iterator;
    const auto begin = make_filter_iterator(p, std::cbegin(foos), std::cend(foos));
    const auto end   = make_filter_iterator(p, std::cend(foos), std::cend(foos));
    std::cout << std::distance(begin, end) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

一些观察:

  • 海湾合作委员会-O2按预期进行优化或回报较少.
  • Clang(3.8)返回任何优化级别的正确答案.
  • 更改std::dequestd::vectorstd::list在预期的行为结果.
  • 14很关键; 什么都没有,问题就消失了.
  • sizeof(Foo)很重要; 移除sa使问题消失.
  • test通过引用捕获,或仅仅与常量表达式(例如foo.bar == " ")比较导致正常行为.
  • 没有编译器警告(带-Wall -Wextra -pedantic).
  • Valgrind报告没有错误.
  • 使用fsanitize=undefined和问题消失了.

这是怎么回事?

Dan*_*iel 4

此行为是由于向量化优化不当导致的GCC 错误造成的。现已发布修复程序,该修复程序应该会出现在 GCC 6.3 中。

对于那些坚持使用 GCC 5.4 - 6.2 的人,编译器选项-fno-tree-slp-vectorize将“修复”该问题。