From 222e2a7620e6520ffaf4fc4e69d79c18da31542e Mon Sep 17 00:00:00 2001 From: "Zancanaro; Carlo" Date: Mon, 24 Sep 2012 09:58:17 +1000 Subject: Add the clang library to the repo (with some of my changes, too). --- clang/test/SemaCXX/discrim-union.cpp | 118 +++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 clang/test/SemaCXX/discrim-union.cpp (limited to 'clang/test/SemaCXX/discrim-union.cpp') diff --git a/clang/test/SemaCXX/discrim-union.cpp b/clang/test/SemaCXX/discrim-union.cpp new file mode 100644 index 0000000..15c9a22 --- /dev/null +++ b/clang/test/SemaCXX/discrim-union.cpp @@ -0,0 +1,118 @@ +// RUN: %clang_cc1 -std=c++11 %s -fsyntax-only -fcxx-exceptions + +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +template constexpr T &&forward(typename remove_reference::type &t) noexcept { return static_cast(t); } +template constexpr T &&forward(typename remove_reference::type &&t) noexcept { return static_cast(t); } +template constexpr typename remove_reference::type &&move(T &&t) noexcept { return static_cast::type&&>(t); } + +template T declval() noexcept; + +namespace detail { + template struct select {}; // : integral_constant {}; + template struct type {}; + + template union either_impl; + + template<> union either_impl<> { + void get(...); + void destroy(...) { throw "logic_error"; } + }; + + template union either_impl { + private: + T val; + either_impl rest; + typedef either_impl rest_t; + + public: + constexpr either_impl(select<0>, T &&t) : val(move(t)) {} + + template + constexpr either_impl(select, U &&u) : rest(select(), move(u)) {} + + constexpr static unsigned index(type) { return 0; } + template + constexpr static unsigned index(type t) { + return decltype(rest)::index(t) + 1; + } + + void destroy(unsigned elem) { + if (elem) + rest.destroy(elem - 1); + else + val.~T(); + } + + constexpr const T &get(select<0>) { return val; } + template constexpr const decltype(static_cast(rest).get(select{})) get(select) { + return rest.get(select{}); + } + }; +} + +template +struct a { + T value; + template + constexpr a(U &&...u) : value{forward(u)...} {} +}; +template using an = a; + +template T throw_(const U &u) { throw u; } + +template +class either { + unsigned elem; + detail::either_impl impl; + typedef decltype(impl) impl_t; + +public: + template + constexpr either(a &&t) : + elem(impl_t::index(detail::type())), + impl(detail::select())>(), move(t.value)) {} + + // Destruction disabled to allow use in a constant expression. + // FIXME: declare a destructor iff any element has a nontrivial destructor + //~either() { impl.destroy(elem); } + + constexpr unsigned index() noexcept { return elem; } + + template using const_get_result = + decltype(static_cast(impl).get(detail::select{})); + + template + constexpr const_get_result get() { + // Can't just use throw here, since that makes the conditional a prvalue, + // which means we return a reference to a temporary. + return (elem != N ? throw_>("bad_either_get") + : impl.get(detail::select{})); + } + + template + constexpr const U &get() { + return get())>(); + } +}; + +typedef either icd; +constexpr icd icd1 = an(4); +constexpr icd icd2 = a('x'); +constexpr icd icd3 = a(6.5); + +static_assert(icd1.get() == 4, ""); +static_assert(icd2.get() == 'x', ""); +static_assert(icd3.get() == 6.5, ""); + +struct non_triv { + constexpr non_triv() : n(5) {} + int n; +}; +constexpr either icd4 = a(&icd2); +constexpr either icd5 = a(); + +static_assert(icd4.get()->get() == 'x', ""); +static_assert(icd5.get().n == 5, ""); -- cgit v1.2.3