Skip to content

Instantly share code, notes, and snippets.

@ldionne
Created May 23, 2018 01:52
Show Gist options
  • Save ldionne/b4e64b1bfa9c3ec38c53aed3f017692b to your computer and use it in GitHub Desktop.
Save ldionne/b4e64b1bfa9c3ec38c53aed3f017692b to your computer and use it in GitHub Desktop.
example of bad codegen with Hana
#include <cstddef>
#include <type_traits>
#include <utility>
//////////////////////////////////////////////////////////////////////////////
// Utilities required to make the bug report self-contained.
//
// Basically, this defines a very minimal tuple<> structure along with a
// function (operator+) which allows appending an element to a tuple. We
// use operator+ because it makes it easier to see what's going on in the
// test cases below.
//////////////////////////////////////////////////////////////////////////////
template <std::size_t i, typename T>
struct element { T storage; };
template <typename Indices, typename ...T>
struct tuple_base;
template <>
struct tuple_base<std::index_sequence<>> { };
template <std::size_t ...i, typename ...T>
struct tuple_base<std::index_sequence<i...>, T...>
: element<i, T>...
{
constexpr tuple_base() = default;
constexpr tuple_base(T const& ...t)
: element<i, T>{t}...
{ }
};
template <typename ...T>
struct tuple
: tuple_base<std::make_index_sequence<sizeof...(T)>, T...>
{
using Base = tuple_base<std::make_index_sequence<sizeof...(T)>, T...>;
using Base::Base;
};
template <std::size_t ...i, typename ...T, typename U>
constexpr tuple<T..., U>
operator+(tuple_base<std::index_sequence<i...>, T...>&& xs, U u) {
return {static_cast<element<i, T>&&>(std::move(xs)).storage..., u};
}
//////////////////////////////////////////////////////////////////////////////
// Define dumb structures without any "actual" data in it. I know the
// standard still requires them to have a nonzero size, but these are
// still "conceptually" empty in the sense that they are types with a
// single valid value, i.e. the default-constructed one.
//////////////////////////////////////////////////////////////////////////////
struct Empty1 { };
struct Empty { Empty1 e1; Empty1 e2; Empty1 e3; };
//////////////////////////////////////////////////////////////////////////////
// Define a function which appends 21 "empty" structs to a tuple.
//
// The number 21 is important, since the function is inlined if we only append
// 20 elements to the tuple.
//
// Also, when the function is marked as inline, the problem goes away; the
// function is properly inlined and `main` does not call `f()`.
//////////////////////////////////////////////////////////////////////////////
// inline
auto f() {
return tuple<>{}
+ Empty{} + Empty{} + Empty{} + Empty{} + Empty{} + Empty{} + Empty{}
+ Empty{} + Empty{} + Empty{} + Empty{} + Empty{} + Empty{} + Empty{}
+ Empty{} + Empty{} + Empty{} + Empty{} + Empty{} + Empty{} + Empty{}
;
}
int main() {
f();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment