#include <utility>
template <typename P, typename F>
struct foo
{
P _p;
int i{0};
foo(P&& p, F) : _p{std::move(p)} { }
template <typename... Cs>
void up(Cs&... cs)
{
if constexpr(sizeof...(Cs) == 2) { down(cs...); }
else { _p.up(*this, cs...); }
}
void down() { --i; }
template <typename C, typename... Cs>
void down(C& c, Cs&... cs)
{
[&] { [&] { c.down(cs...); }(); }();
}
};
int main()
{
auto f = foo{foo{foo{0, 0}, 0}, 0};
f.up();
}
The code snippet above:
Always segfaults on execution when compiled with g++ 7.1 and trunk, with
-O0.Always reports errors on execution when compiled with g++ 7.1 and trunk, with any optimization level and either
-fsanitize=addressor-fsanitize=undefined.Never segfaults or report any sanitizer error with clang++ 5 and trunk.
Taking any of the following actions:
Getting rid of
--i;fromdown().Changing
[&] { [&] { c.down(cs...); }(); }();to[&] { c.down(cs...); }();.Removing
typename Fand updating the constructor accordingly.Changing
foo{foo{foo{0, 0}, 0}, 0}tofoo{foo{0, 0}, 0}.
Fixes the segmentation fault and prevents any sanitizer error.
What's going on here? Is my code ill-formed, or is this a weird gcc bug that produces wrong assembly?