blob: 698458f0e9a5f1f9a92601027075bc5b330a2699 [file] [log] [blame]
/* { dg-do compile } */
/* { dg-options "-O2 -std=gnu++14 -fdump-tree-sra" } */
#include <utility>
#define EGGS_CXX11_CONSTEXPR constexpr
#define EGGS_CXX11_STATIC_CONSTEXPR static constexpr
#define EGGS_CXX14_CONSTEXPR constexpr
#define EGGS_CXX11_NOEXCEPT noexcept
namespace eggs { namespace variants { namespace detail
{
struct empty
{
EGGS_CXX11_CONSTEXPR bool operator==(empty) const { return true; }
EGGS_CXX11_CONSTEXPR bool operator<(empty) const { return false; }
};
template <typename T>
struct identity
{
using type = T;
};
template <std::size_t I>
struct index
{
EGGS_CXX11_STATIC_CONSTEXPR std::size_t value = I;
};
template <typename ...Ts>
struct pack
{
using type = pack;
EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = sizeof...(Ts);
};
template <typename T, T ...Vs>
struct pack_c
{
using type = pack_c;
EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = sizeof...(Vs);
};
///////////////////////////////////////////////////////////////////////////
template <typename Is, bool Odd>
struct _make_index_pack_twice;
template <std::size_t ...Is>
struct _make_index_pack_twice<
pack_c<std::size_t, Is...>
, false
> : pack_c<std::size_t, Is..., (sizeof...(Is) + Is)...>
{};
template <std::size_t ...Is>
struct _make_index_pack_twice<
pack_c<std::size_t, Is...>
, true
> : pack_c<std::size_t, Is..., (sizeof...(Is) + Is)..., sizeof...(Is) * 2>
{};
template <std::size_t N>
struct _make_index_pack
: _make_index_pack_twice<
typename _make_index_pack<N / 2>::type
, N % 2 != 0
>
{};
template <>
struct _make_index_pack<1>
: pack_c<std::size_t, 0>
{};
template <>
struct _make_index_pack<0>
: pack_c<std::size_t>
{};
template <std::size_t N>
using make_index_pack = typename _make_index_pack<N>::type;
template <typename Ts>
struct _index_pack;
template <typename ...Ts>
struct _index_pack<pack<Ts...>>
: _make_index_pack<sizeof...(Ts)>
{};
template <typename Ts>
using index_pack = typename _index_pack<Ts>::type;
///////////////////////////////////////////////////////////////////////////
template <typename Vs>
struct all_of;
template <bool ...Vs>
struct all_of<pack_c<bool, Vs...>>
: std::integral_constant<
bool
, std::is_same<
pack_c<bool, Vs...>
, pack_c<bool, (Vs || true)...> // true...
>::value
>
{};
template <typename ...Ts>
struct all_of<pack<Ts...>>
: all_of<pack_c<bool, (Ts::value)...>>
{};
template <typename ...Vs>
struct any_of;
template <bool ...Vs>
struct any_of<pack_c<bool, Vs...>>
: std::integral_constant<
bool
, !all_of<pack_c<bool, !Vs...>>::value
>
{};
template <typename ...Ts>
struct any_of<pack<Ts...>>
: any_of<pack_c<bool, (Ts::value)...>>
{};
///////////////////////////////////////////////////////////////////////////
template <std::size_t I, typename T>
struct _indexed {};
template <typename Ts, typename Is = index_pack<Ts>>
struct _indexer;
template <typename ...Ts, std::size_t ...Is>
struct _indexer<pack<Ts...>, pack_c<std::size_t, Is...>>
: _indexed<Is, Ts>...
{};
empty _at_index(...);
template <std::size_t I, typename T>
identity<T> _at_index(_indexed<I, T> const&);
template <std::size_t I, typename Ts>
struct at_index
: decltype(_at_index<I>(_indexer<Ts>{}))
{};
empty _index_of(...);
template <typename T, std::size_t I>
index<I> _index_of(_indexed<I, T> const&);
template <typename T, typename Ts>
struct index_of
: decltype(_index_of<T>(_indexer<Ts>{}))
{};
}}}
namespace eggs { namespace variants { namespace detail
{
template <typename Ts, bool IsTriviallyDestructible>
struct _union;
///////////////////////////////////////////////////////////////////////////
template <bool IsTriviallyDestructible>
struct _union<pack<>, IsTriviallyDestructible>
{};
template <typename T, typename ...Ts>
struct _union<pack<T, Ts...>, true>
{
EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = 1 + sizeof...(Ts);
template <typename ...Args>
EGGS_CXX11_CONSTEXPR _union(index<0>, Args&&... args)
: _head(std::forward<Args>(args)...)
{}
template <std::size_t I, typename ...Args>
EGGS_CXX11_CONSTEXPR _union(index<I>, Args&&... args)
: _tail(index<I - 1>{}, std::forward<Args>(args)...)
{}
EGGS_CXX14_CONSTEXPR void* target() EGGS_CXX11_NOEXCEPT
{
return &_target;
}
EGGS_CXX11_CONSTEXPR void const* target() const EGGS_CXX11_NOEXCEPT
{
return &_target;
}
EGGS_CXX14_CONSTEXPR T& get(index<0>) EGGS_CXX11_NOEXCEPT
{
return this->_head;
}
EGGS_CXX11_CONSTEXPR T const& get(index<0>) const EGGS_CXX11_NOEXCEPT
{
return this->_head;
}
template <
std::size_t I
, typename U = typename at_index<I, pack<T, Ts...>>::type
>
EGGS_CXX14_CONSTEXPR U& get(index<I>) EGGS_CXX11_NOEXCEPT
{
return this->_tail.get(index<I - 1>{});
}
template <
std::size_t I
, typename U = typename at_index<I, pack<T, Ts...>>::type
>
EGGS_CXX11_CONSTEXPR U const& get(index<I>) const EGGS_CXX11_NOEXCEPT
{
return this->_tail.get(index<I - 1>{});
}
private:
union
{
char _target;
T _head;
_union<pack<Ts...>, true> _tail;
};
};
///////////////////////////////////////////////////////////////////////////
template <typename Ts, bool TriviallyCopyable, bool TriviallyDestructible>
struct _storage;
template <typename ...Ts>
struct _storage<pack<Ts...>, true, true>
: _union<
pack<Ts...>
, all_of<pack<std::is_trivially_destructible<Ts>...>>::value
>
{
using base_type = _union<
pack<Ts...>
, all_of<pack<std::is_trivially_destructible<Ts>...>>::value
>;
EGGS_CXX11_CONSTEXPR _storage() EGGS_CXX11_NOEXCEPT
: base_type{index<0>{}}
, _which{0}
{}
_storage(_storage const& rhs) = default;
_storage(_storage&& rhs) = default;
template <std::size_t I, typename ...Args>
EGGS_CXX11_CONSTEXPR _storage(index<I> which, Args&&... args)
: base_type{which, std::forward<Args>(args)...}
, _which{I}
{}
_storage& operator=(_storage const& rhs) = default;
_storage& operator=(_storage&& rhs) = default;
EGGS_CXX11_CONSTEXPR std::size_t which() const
{
return _which;
}
using base_type::target;
using base_type::get;
protected:
std::size_t _which;
};
template <typename ...Ts>
using storage = _storage<
pack<empty, Ts...>
, all_of<pack<std::is_trivially_copyable<Ts>...>>::value
, all_of<pack<std::is_trivially_destructible<Ts>...>>::value
>;
}}}
namespace eggs { namespace variants
{
template <typename ...Ts>
class variant;
namespace detail
{
///////////////////////////////////////////////////////////////////////
namespace _best_match
{
template <typename Ts, std::size_t I = 0>
struct overloads
{};
template <typename T, typename ...Ts, std::size_t I>
struct overloads<pack<T, Ts...>, I>
: overloads<pack<Ts...>, I + 1>
{
using fun_ptr = index<I>(*)(T);
operator fun_ptr();
};
template <typename F, typename T>
auto _invoke(F&&, T&&)
-> decltype(std::declval<F>()(std::declval<T>()));
struct _fallback {};
_fallback _invoke(...);
template <
typename T, typename U
, typename R = decltype(_best_match::_invoke(
std::declval<T>(), std::declval<U>()))
>
struct result_of : R
{};
template <typename T, typename U>
struct result_of<T, U, _fallback>
{};
}
template <typename U, typename ...Ts>
struct index_of_best_match
: _best_match::result_of<_best_match::overloads<Ts...>, U>
{};
}
template <typename ...Ts>
class variant
{
public:
EGGS_CXX11_CONSTEXPR variant() EGGS_CXX11_NOEXCEPT = delete;
variant(variant const& rhs) = default;
variant(variant&& rhs) = default;
template <
typename U
, typename Enable = typename std::enable_if<!std::is_same<
typename std::decay<U>::type, variant
>::value>::type
, std::size_t I = detail::index_of_best_match<
U&&, detail::pack<Ts...>>::value
, typename T = typename detail::at_index<
I, detail::pack<Ts...>>::type
>
EGGS_CXX11_CONSTEXPR variant(U&& v)
noexcept(
std::is_nothrow_constructible<T, U&&>::value)
: _storage{detail::index<I + 1>{}, std::forward<U>(v)}
{}
~variant() = default;
variant& operator=(variant const& rhs) = delete;
private:
detail::storage<Ts...> _storage;
};
}}
template <class T, class Base>
struct ref_proxy : Base
{
using Base::Base;
ref_proxy()
: Base()
{
}
ref_proxy(Base ptr)
: Base(std::move(ptr))
{
}
};
template <class T>
struct inplace_ref
{
explicit inplace_ref(T inner)
: inner_(inner)
{
}
T inner_;
};
template <class ...Variants>
struct variant_ref
{
variant_ref() = delete;
explicit variant_ref(eggs::variants::variant<Variants...> t)
: inner_storage_(t)
{
}
template <class Source>
variant_ref(ref_proxy<Source, variant_ref> ptr)
: inner_storage_(ptr.inner_storage_)
{}
private:
eggs::variants::variant<Variants...> inner_storage_;
};
struct option_1
{
void *a, *b, *c, *d, *e;
};
struct option_2
{
};
using option_ref = variant_ref<option_1, option_2>;
struct qual_option
{
qual_option(ref_proxy<void, option_ref > type, int quals)
: type_(type)
, quals_(quals)
{
}
explicit qual_option(ref_proxy<void, option_ref > type)
: qual_option(type, 0)
{
}
ref_proxy<void, option_ref > type_;
int quals_;
};
inline ref_proxy<option_2, option_ref > make_object_1()
{
return ref_proxy<option_2, option_ref >(option_2());
}
inline ref_proxy<option_2, option_ref > make_object_2()
{
return make_object_1();
}
inline inplace_ref<qual_option> make_object_3(ref_proxy<option_2, option_ref>&& a0)
{
return inplace_ref<qual_option>(qual_option(a0));
}
inline ref_proxy<qual_option, inplace_ref<qual_option> > make_object_4(ref_proxy<option_2, option_ref>&& a0)
{
return make_object_3(std::move(a0));
}
ref_proxy<qual_option, inplace_ref<qual_option> > f() __attribute__((noinline));
ref_proxy<qual_option, inplace_ref<qual_option> > f()
{
return make_object_4(make_object_2());
}
int main(int argc, char* argv[])
{
for (;;)
f();
}
/* { dg-final { scan-tree-dump "Removing load:.*ptr;" "sra" } } */