Created
May 23, 2018 01:52
-
-
Save ldionne/b4e64b1bfa9c3ec38c53aed3f017692b to your computer and use it in GitHub Desktop.
example of bad codegen with Hana
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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