Index: include/variant =================================================================== --- /dev/null +++ include/variant @@ -0,0 +1,1257 @@ +// -*- C++ -*- +//===------------------------------ variant -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_VARIANT +#define _LIBCPP_VARIANT + +/* + variant synopsis + +namespace std { + + // 20.7.2, class template variant + template + class variant { + public: + + // 20.7.2.1, constructors + constexpr variant() noexcept(see below); + variant(const variant&); + variant(variant&&) noexcept(see below); + + template constexpr variant(T&&) noexcept(see below); + + template + constexpr explicit variant(in_place_type_t, Args&&...); + + template + constexpr explicit variant( + in_place_type_t, initializer_list, Args&&...); + + template + constexpr explicit variant(in_place_index_t, Args&&...); + + template + constexpr explicit variant( + in_place_index_t, initializer_list, Args&&...); + + // 20.7.2.2, destructor + ~variant(); + + // 20.7.2.3, assignment + variant& operator=(const variant&); + variant& operator=(variant&&) noexcept(see below); + + template variant& operator=(T&&) noexcept(see below); + + // 20.7.2.4, modifiers + template + void emplace(Args&&...); + + template + void emplace(initializer_list, Args&&...); + + template + void emplace(Args&&...); + + template + void emplace(initializer_list, Args&&...); + + // 20.7.2.5, value status + constexpr bool valueless_by_exception() const noexcept; + constexpr size_t index() const noexcept; + + // 20.7.2.6, swap + void swap(variant&) noexcept(see below); + }; + + // 20.7.3, variant helper classes + template struct variant_size; // undefined + + template + constexpr size_t variant_size_v = variant_size::value; + + template struct variant_size; + template struct variant_size; + template struct variant_size; + + template + struct variant_size>; + + template struct variant_alternative; // undefined + + template + using variant_alternative_t = typename variant_alternative::type; + + template struct variant_alternative; + template struct variant_alternative; + template struct variant_alternative; + + template + struct variant_alternative>; + + constexpr size_t variant_npos = -1; + + // 20.7.4, value access + template + constexpr bool holds_alternative(const variant&) noexcept; + + template + constexpr variant_alternative_t>& + get(variant&); + + template + constexpr variant_alternative_t>&& + get(variant&&); + + template + constexpr variant_alternative_t> const& + get(const variant&); + + template + constexpr variant_alternative_t> const&& + get(const variant&&); + + template + constexpr T& get(variant&); + + template + constexpr T&& get(variant&&); + + template + constexpr const T& get(const variant&); + + template + constexpr const T&& get(const variant&&); + + template + constexpr add_pointer_t>> + get_if(variant*) noexcept; + + template + constexpr add_pointer_t>> + get_if(const variant*) noexcept; + + template + constexpr add_pointer_t + get_if(variant*) noexcept; + + template + constexpr add_pointer_t + get_if(const variant*) noexcept; + + // 20.7.5, relational operators + template + constexpr bool operator==(const variant&, const variant&); + + template + constexpr bool operator!=(const variant&, const variant&); + + template + constexpr bool operator<(const variant&, const variant&); + + template + constexpr bool operator>(const variant&, const variant&); + + template + constexpr bool operator<=(const variant&, const variant&); + + template + constexpr bool operator>=(const variant&, const variant&); + + // 20.7.6, visitation + template + constexpr see below visit(Visitor&&, Variants&&...); + + // 20.7.7, class monostate + struct monostate; + + // 20.7.8, monostate relational operators + constexpr bool operator<(monostate, monostate) noexcept; + constexpr bool operator>(monostate, monostate) noexcept; + constexpr bool operator<=(monostate, monostate) noexcept; + constexpr bool operator>=(monostate, monostate) noexcept; + constexpr bool operator==(monostate, monostate) noexcept; + constexpr bool operator!=(monostate, monostate) noexcept; + + // 20.7.9, specialized algorithms + template + void swap(variant&, variant&) noexcept(see below); + + // 20.7.10, class bad_variant_access + class bad_variant_access; + + // 20.7.11, hash support + template struct hash; + template struct hash>; + template <> struct hash; + +} // namespace std + +*/ + +#include <__config> +#include <__tuple> +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +namespace std { // explicitly not using versioning namespace + +class _LIBCPP_EXCEPTION_ABI bad_variant_access : public exception { +public: + virtual const char* what() const noexcept; +}; + +} // namespace std + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 14 + +template +class _LIBCPP_TYPE_VIS variant; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size; + +template +constexpr size_t variant_size_v = variant_size<_Tp>::value; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size + : variant_size<_Tp> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size + : variant_size<_Tp> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size + : variant_size<_Tp> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_size> + : integral_constant {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative; + +template +using variant_alternative_t = typename variant_alternative<_Ip, _Tp>::type; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative<_Ip, const _Tp> + : add_const> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative<_Ip, volatile _Tp> + : add_volatile> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative<_Ip, const volatile _Tp> + : add_cv> {}; + +template +struct _LIBCPP_TYPE_VIS_ONLY variant_alternative<_Ip, variant<_Types...>> + : __identity<__type_pack_element<_Ip, _Types...>> {}; + +constexpr size_t variant_npos = static_cast(-1); + +struct __variant_valueless_t {}; +constexpr __variant_valueless_t __variant_valueless = __variant_valueless_t{}; + +namespace __find_detail { + + template + constexpr size_t __find_index() { + constexpr bool __matches[] = {is_same_v<_Tp, _Types>...}; + size_t __result = __not_found; + for (size_t __i = 0; __i < sizeof...(_Types); ++__i) { + if (__matches[__i]) { + if (__result != __not_found) { + return __ambiguous; + } + __result = __i; + } + } + return __result; + } + + template + struct __find_unambiguous_index_sfinae_impl + : integral_constant {}; + + template <> + struct __find_unambiguous_index_sfinae_impl<__not_found> {}; + + template <> + struct __find_unambiguous_index_sfinae_impl<__ambiguous> {}; + + template + struct __find_unambiguous_index_sfinae + : __find_unambiguous_index_sfinae_impl<__find_index<_Tp, _Types...>()> {}; + +} // namespace __find_detail + +using __find_detail::__find_unambiguous_index_sfinae; + +template +class __variant_overload; + +template <> +class __variant_overload<> { +public: + void operator()() const; +}; + +template +class __variant_overload<_Tp, _Types...> + : public __variant_overload<_Types...> { +public: + using __variant_overload<_Types...>::operator(); + __identity<_Tp> operator()(_Tp) const; +}; + +template +using __variant_best_match = + typename result_of_t<__variant_overload<_Types...>(_Tp)>::type; + +struct __variant_union_access { + template + static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<0>) { + return _VSTD::forward<_Vp>(__v).__head; + } + + template + static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<_Ip>) { + return __get_alt(_VSTD::forward<_Vp>(__v).__tail, in_place_index<_Ip - 1>); + } +}; + +struct __variant_impl_access { + template + static constexpr auto&& __get_alt(_Vp&& __v) { + return __variant_union_access::__get_alt(_VSTD::forward<_Vp>(__v).__data, + in_place_index<_Ip>); + } +}; + +struct __variant_access { + template + static constexpr auto&& __get_alt(_Vp&& __v) { + return __variant_impl_access::__get_alt<_Ip>( + _VSTD::forward<_Vp>(__v).__impl); + } +}; + +namespace __variant_impl_visitation_detail { + + template + constexpr const _Tp& __at_impl(const _Tp& __elem, const size_t*) { + return __elem; + } + + template + constexpr auto&& __at_impl(const array<_Tp, _Np>& __elems, + const size_t* __index) { + return __at_impl(__elems[*__index], __index + 1); + } + + template + constexpr auto&& __at(const array<_Tp, _Np>& __elems, + const size_t (&__indices)[_Ip]) { + return __at_impl(__elems, begin(__indices)); + } + + template + struct __all_same : __all...> {}; + + template + constexpr void __variant_visit_has_same_return_types(true_type) {} + + template + constexpr void __variant_visit_has_same_return_types(false_type) = delete; + + template + constexpr array...>, sizeof...(_Args)> + __make_array(_Args&&... __args) { + using __all_same = __all_same...>; + __variant_visit_has_same_return_types...>(__all_same{}); + return {{_VSTD::forward<_Args>(__args)...}}; + } + + template + constexpr auto __make_dispatch(index_sequence<_Is...>) { + struct __dispatcher { + static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) { + return __invoke_constexpr( + static_cast<_Fp>(__f), + __variant_impl_access::__get_alt<_Is>(static_cast<_Vs>(__vs))...); + } + }; + return _VSTD::addressof(__dispatcher::__dispatch); + } + + template + constexpr auto __make_fdiagonal_impl() { + return __make_dispatch<_Fp, _Vs...>( + index_sequence<(__identity<_Vs>{}, _Ip)...>{}); + } + + template + constexpr auto __make_fdiagonal_impl(index_sequence<_Is...>) { + return __make_array(__make_fdiagonal_impl<_Is, _Fp, _Vs...>()...); + } + + template + constexpr auto __make_fdiagonal() { + constexpr size_t _Np = decay_t<_Vp>::__size(); + static_assert(__all<(_Np == decay_t<_Vs>::__size())...>::value); + return __make_fdiagonal_impl<_Fp, _Vp, _Vs...>(make_index_sequence<_Np>{}); + } + + template + constexpr auto __make_fmatrix_impl(index_sequence<_Is...> __is) { + return __make_dispatch<_Fp, _Vs...>(__is); + } + + template + constexpr auto __make_fmatrix_impl(index_sequence<_Is...>, + index_sequence<_Js...>, + _Ls... __ls) { + return __make_array(__make_fmatrix_impl<_Fp, _Vs...>( + index_sequence<_Is..., _Js>{}, __ls...)...); + } + + template + constexpr auto __make_fmatrix() { + return __make_fmatrix_impl<_Fp, _Vs...>( + index_sequence<>{}, make_index_sequence::__size()>{}...); + } + +} // namespace __variant_impl_visitation_detail + +struct __variant_impl_visitation { + template + static constexpr decltype(auto) __visit_alt_at(size_t __index, + _Visitor&& __visitor, + _Vs&&... __vs) { + using namespace __variant_impl_visitation_detail; + constexpr auto __fdiagonal = __make_fdiagonal< + _Visitor&&, + decltype(_VSTD::forward<_Vs>(__vs).__as_variant_base())...>(); + return __fdiagonal[__index]( + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__as_variant_base()...); + } + + template + static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, + _Vs&&... __vs) { + using namespace __variant_impl_visitation_detail; + constexpr auto __fmatrix = __make_fmatrix< + _Visitor&&, + decltype(_VSTD::forward<_Vs>(__vs).__as_variant_base())...>(); + const size_t __indices[] = {__vs.index()...}; + return __at(__fmatrix, __indices)( + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__as_variant_base()...); + } +}; + +struct __variant_visitation { + template + static constexpr decltype(auto) __visit_alt_at(size_t __index, + _Visitor&& __visitor, + _Vs&&... __vs) { + return __variant_impl_visitation::__visit_alt_at( + __index, + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__impl...); + } + + template + static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, + _Vs&&... __vs) { + return __variant_impl_visitation::__visit_alt( + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__impl...); + } + + template + struct __value_visitor { + template + constexpr decltype(auto) operator()(_Alts&&... __alts) const { + return __invoke_constexpr(static_cast<_Visitor>(__visitor), + _VSTD::forward<_Alts>(__alts).__get_value()...); + } + + _Visitor __visitor; + }; + + template + static constexpr auto __make_value_visitor(_Visitor&& __visitor) { + return __value_visitor<_Visitor&&>{_VSTD::forward<_Visitor>(__visitor)}; + } + + template + static constexpr decltype(auto) __visit_value_at(size_t __index, + _Visitor&& __visitor, + _Vs&&... __vs) { + return __visit_alt_at( + __index, + __make_value_visitor(_VSTD::forward<_Visitor>(__visitor)), + _VSTD::forward<_Vs>(__vs)...); + } + + template + static constexpr decltype(auto) __visit_value(_Visitor&& __visitor, + _Vs&&... __vs) { + return __visit_alt( + __make_value_visitor(_VSTD::forward<_Visitor>(__visitor)), + _VSTD::forward<_Vs>(__vs)...); + } +}; + +template +struct _LIBCPP_TYPE_VIS_ONLY __variant_alt { + using __value_type = _Tp; + + __variant_alt() = default; + __variant_alt(const __variant_alt&) = delete; + __variant_alt(__variant_alt&&) = delete; + __variant_alt& operator=(const __variant_alt&) = delete; + __variant_alt& operator=(__variant_alt&&) = delete; + + template + explicit constexpr __variant_alt(_Args&&... __args) + : __value(_VSTD::forward<_Args>(__args)...) {} + + constexpr auto&& __get_value() & { + return static_cast<__value_type&>(__value); + } + + constexpr auto&& __get_value() && { + return static_cast<__value_type&&>(__value); + } + + constexpr auto&& __get_value() const & { + return static_cast(__value); + } + + constexpr auto&& __get_value() const && { + return static_cast(__value); + } + +private: + __value_type __value; +}; + +template +union __variant_union; + +template +union __variant_union<__trivially_destructible, __index> {}; + +#define _LIBCPP_VARIANT_UNION(__trivially_destructible, dtor) \ + template \ + union __variant_union<__trivially_destructible, __index, _Tp, _Types...> { \ + public: \ + explicit constexpr __variant_union(__variant_valueless_t) noexcept \ + : __dummy{} {} \ + \ + template \ + explicit constexpr __variant_union(in_place_index_t<0>, \ + _Args&&... __args) \ + : __head(_VSTD::forward<_Args>(__args)...) {} \ + \ + template \ + explicit constexpr __variant_union(in_place_index_t<_Ip>, \ + _Args&&... __args) \ + : __tail(in_place_index<_Ip - 1>, _VSTD::forward<_Args>(__args)...) {} \ + \ + dtor \ + \ + private: \ + char __dummy; \ + __variant_alt<__index, _Tp> __head; \ + __variant_union<__trivially_destructible, __index + 1, _Types...> __tail; \ + \ + friend struct __variant_union_access; \ + } + +_LIBCPP_VARIANT_UNION(true , ~__variant_union() = default;); +_LIBCPP_VARIANT_UNION(false, ~__variant_union() {}); + +#undef _LIBCPP_VARIANT_UNION + +template +class __variant_base { +public: + static constexpr size_t __size() { return sizeof...(_Types); } + + explicit constexpr __variant_base(__variant_valueless_t) noexcept + : __index(variant_npos), __data(__variant_valueless) {} + + template + explicit constexpr __variant_base(in_place_index_t<_Ip>, _Args&&... __args) + : __index(_Ip), __data(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...) {} + + constexpr bool valueless_by_exception() const noexcept { + return index() == variant_npos; + } + + constexpr size_t index() const noexcept { return __index; } + +protected: + constexpr auto&& __as_variant_base() & { return *this; } + constexpr auto&& __as_variant_base() && { return _VSTD::move(*this); } + constexpr auto&& __as_variant_base() const & { return *this; } + constexpr auto&& __as_variant_base() const && { return _VSTD::move(*this); } + + size_t __index; + __variant_union<__trivially_destructible, 0, _Types...> __data; + + friend struct __variant_impl_access; + friend struct __variant_impl_visitation; +}; + +// Provides the appropriate destructor and a `__destroy` function based on +// whether all types of alternatives are `__trivially_destructible`. +template +class __variant_dtor; + +template +class __variant_dtor + : public __variant_base { + using __base_type = __variant_base; + +public: + using __base_type::__base_type; + ~__variant_dtor() = default; + +protected: + void __destroy() noexcept { this->__index = variant_npos; } +}; + +template +class __variant_dtor + : public __variant_base { + using __base_type = __variant_base; + +public: + using __base_type::__base_type; + ~__variant_dtor() { __destroy(); } + +protected: + void __destroy() noexcept { + if (!this->valueless_by_exception()) { + __variant_impl_visitation::__visit_alt( + [](auto& __alt) noexcept { + using __alt_type = decay_t; + __alt.~__alt_type(); + }, + *this); + } + this->__index = variant_npos; + } +}; + +template +struct __variant_impl + : public __variant_dtor< + __all...>::value, _Types...> { + using __base_type = + __variant_dtor<__all...>::value, + _Types...>; + +public: + using __base_type::__base_type; + + __variant_impl( + const conditional_t<__all...>::value, + __variant_impl, + __nat>& __that) + : __variant_impl(__variant_valueless) { + static_assert(!is_same_v, __nat>); + __generic_construct(*this, __that); + } + + __variant_impl( + conditional_t<__all...>::value, + __variant_impl, + __nat>&& + __that) + noexcept(__all...>::value) + : __variant_impl(__variant_valueless) { + static_assert(!is_same_v, __nat>); + __generic_construct(*this, _VSTD::move(__that)); + } + + __variant_impl& operator=( + const conditional_t<__all<(is_copy_constructible_v<_Types> && + is_move_constructible_v<_Types> && + is_copy_assignable_v<_Types>)...>::value, + __variant_impl, + __nat>& __that) { + static_assert(!is_same_v, __nat>); + return __generic_assign(__that); + } + + __variant_impl& operator=( + conditional_t<__all<(is_move_constructible_v<_Types> && + is_move_assignable_v<_Types>)...>::value, + __variant_impl, + __nat>&& + __that) noexcept(__all<(is_nothrow_move_constructible_v<_Types> && + is_nothrow_move_assignable_v<_Types>)...>::value) { + static_assert(!is_same_v, __nat>); + return __generic_assign(_VSTD::move(__that)); + } + + template + void __assign(_Arg&& __arg) { + __assign_alt(__variant_impl_access::__get_alt<_Ip>(*this), + _VSTD::forward<_Arg>(__arg), + false_type{}); + } + + template + void __emplace(_Args&&... __args) { + this->__destroy(); + __construct_alt(__variant_impl_access::__get_alt<_Ip>(*this), + _VSTD::forward<_Args>(__args)...); + this->__index = _Ip; + } + + void __swap(__variant_impl& __that) { + if (this->valueless_by_exception() && __that.valueless_by_exception()) { + // do nothing. + } else if (this->index() == __that.index()) { + __variant_impl_visitation::__visit_alt_at( + this->index(), + [](auto& __this_alt, auto& __that_alt) { + using _VSTD::swap; + swap(__this_alt.__get_value(), __that_alt.__get_value()); + }, + *this, + __that); + } else { + __variant_impl* __lhs = this; + __variant_impl* __rhs = _VSTD::addressof(__that); + if (__lhs->__is_nothrow_move_constructible() && + !__rhs->__is_nothrow_move_constructible()) { + _VSTD::swap(__lhs, __rhs); + } + __variant_impl __tmp(_VSTD::move(*__rhs)); +#ifndef _LIBCPP_NO_EXCEPTIONS + // EXTENSION: When the move construction of `__lhs` into `__rhs` throws + // and `__tmp` is nothrow move constructible then we move `__tmp` back + // into `__rhs` and provide the strong exception safety guarentee. + try { + __generic_construct(*__rhs, _VSTD::move(*__lhs)); + } catch (...) { + if (__tmp.__is_nothrow_move_constructible()) { + __generic_construct(*__rhs, _VSTD::move(__tmp)); + } + throw; + } +#else + __generic_construct(*__rhs, _VSTD::move(*__lhs)); +#endif + __generic_construct(*__lhs, _VSTD::move(__tmp)); + } + } + +private: + bool __is_nothrow_move_constructible() const { + constexpr bool __results[] = {is_nothrow_move_constructible_v<_Types>...}; + return this->valueless_by_exception() || __results[this->index()]; + } + + template + void __assign_alt(__variant_alt<_Ip, _Tp>& __alt, + _Arg&& __arg, + bool_constant<__copy_assign> __tag) { + if (this->index() == _Ip) { + __alt.__get_value() = _VSTD::forward<_Arg>(__arg); + } else { + struct { + void operator()(true_type) const { + __this->__emplace<_Ip>(_Tp(static_cast<_Arg&&>(__arg))); + } + void operator()(false_type) const { + __this->__emplace<_Ip>(static_cast<_Arg&&>(__arg)); + } + __variant_impl* __this; + _Arg&& __arg; + } __impl{this, _VSTD::forward<_Arg>(__arg)}; + __impl(__tag); + } + } + + template + __variant_impl& __generic_assign(_That&& __that) { + static_assert(is_same_v, __variant_impl>); + if (this->valueless_by_exception() && __that.valueless_by_exception()) { + // do nothing. + } else if (__that.valueless_by_exception()) { + this->__destroy(); + } else { + __variant_impl_visitation::__visit_alt_at( + __that.index(), + [this](auto& __this_alt, auto&& __that_alt) { + __assign_alt( + __this_alt, + _VSTD::forward(__that_alt).__get_value(), + is_lvalue_reference<_That&&>{}); + }, + *this, + _VSTD::forward<_That>(__that)); + } + return *this; + } + + template + static void __construct_alt(__variant_alt<_Ip, _Tp>& __alt, + _Args&&... __args) { + ::new (_VSTD::addressof(__alt)) + __variant_alt<_Ip, _Tp>(_VSTD::forward<_Args>(__args)...); + } + + template + static void __generic_construct(__variant_impl& __lhs, _Rhs&& __rhs) { + static_assert(is_same_v, __variant_impl>); + __lhs.__destroy(); + if (!__rhs.valueless_by_exception()) { + __variant_impl_visitation::__visit_alt_at( + __rhs.index(), + [](auto& __lhs_alt, auto&& __rhs_alt) { + __construct_alt( + __lhs_alt, + _VSTD::forward(__rhs_alt).__get_value()); + }, + __lhs, + _VSTD::forward<_Rhs>(__rhs)); + __lhs.__index = __rhs.index(); + } + } +}; + +template +class variant { + static_assert(sizeof...(_Types) > 0, + "variant must consist of at least one alternative."); + + static_assert(__all...>::value, + "variant can not have an array type as an alternative."); + + static_assert(__all...>::value, + "variant can not have a reference type as an alternative."); + + static_assert(__all...>::value, + "variant can not have a void type as an alternative."); + +public: + template = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t, int> = 0> + constexpr variant() noexcept(is_nothrow_default_constructible_v<_Tp>) + : __impl(in_place_index<0>) {} + + variant(const variant&) = default; + variant(variant&&) = default; + + template , variant>, int> = 0, + class _Tp = __variant_best_match<_Arg&&, _Types...>, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp, _Types...>::value, + enable_if_t, int> = 0> + constexpr variant(_Arg&&__arg) noexcept( + is_nothrow_constructible_v<_Tp, _Arg&&>) + : __impl(in_place_index<_Ip>, _VSTD::forward<_Arg>(__arg)) {} + + template = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t, int> = 0> + explicit constexpr variant( + in_place_index_t<_Ip>, + _Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, _Args&&...>) + : __impl(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...) {} + + template < + size_t _Ip, + class _Up, + class... _Args, + enable_if_t<(_Ip < sizeof...(_Types)), int> = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t&, _Args&&...>, + int> = 0> + explicit constexpr variant( + in_place_index_t<_Ip>, + initializer_list<_Up> __il, + _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args&&...>) + : __impl(in_place_index<_Ip>, __il, _VSTD::forward<_Args>(__args)...) {} + + template ::value, + enable_if_t, int> = 0> + explicit constexpr variant(in_place_type_t<_Tp>, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Tp, _Args&&...>) + : __impl(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...) {} + + template < + class _Tp, + class _Up, + class... _Args, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp, _Types...>::value, + enable_if_t&, _Args&&...>, + int> = 0> + explicit constexpr variant( + in_place_type_t<_Tp>, + initializer_list<_Up> __il, + _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Tp, initializer_list< _Up>&, _Args&&...>) + : __impl(in_place_index<_Ip>, __il, _VSTD::forward<_Args>(__args)...) {} + + ~variant() = default; + + variant& operator=(const variant&) = default; + variant& operator=(variant&&) = default; + + template , variant>, int> = 0, + class _Tp = __variant_best_match<_Arg&&, _Types...>, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp, _Types...>::value, + enable_if_t<(is_assignable_v<_Tp&, _Arg&&> && + is_constructible_v<_Tp, _Arg&&>), int> = 0> + variant& operator=(_Arg&& __arg) noexcept( + (is_nothrow_assignable_v<_Tp&, _Arg&&> && + is_nothrow_constructible_v<_Tp, _Arg&&>)) { + __impl.template __assign<_Ip>(_VSTD::forward<_Arg>(__arg)); + return *this; + } + + template < + size_t _Ip, + class... _Args, + enable_if_t<(_Ip < sizeof...(_Types)), int> = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t, int> = 0> + void emplace(_Args&&... __args) { + __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); + } + + template < + size_t _Ip, + class _Up, + class... _Args, + enable_if_t<(_Ip < sizeof...(_Types)), int> = 0, + class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, + enable_if_t&, _Args&&...>, + int> = 0> + void emplace(initializer_list<_Up> __il, _Args&&... __args) { + __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); + } + + template < + class _Tp, + class... _Args, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp, _Types...>::value, + enable_if_t, int> = 0> + void emplace(_Args&&... __args) { + __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); + } + + template < + class _Tp, + class _Up, + class... _Args, + size_t _Ip = __find_unambiguous_index_sfinae<_Tp, _Types...>::value, + enable_if_t&, _Args&&...>, + int> = 0> + void emplace(initializer_list<_Up> __il, _Args&&... __args) { + __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); + } + + constexpr bool valueless_by_exception() const noexcept { + return __impl.valueless_by_exception(); + } + + constexpr size_t index() const noexcept { return __impl.index(); } + + template < + bool __dummy = false, + enable_if_t< + __all<( + __dependent_type, __dummy>::value && + __dependent_type, __dummy>::value)...>::value, + int> = 0> + void swap(variant& __that) noexcept( + __all<(is_nothrow_move_constructible_v<_Types> && + is_nothrow_swappable_v<_Types>)...>::value) { + __impl.__swap(__that.__impl); + } + +private: + __variant_impl<_Types...> __impl; + + friend struct __variant_access; + friend struct __variant_visitation; +}; + +template +constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept { + return __v.index() == _Ip; +} + +template +constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { + return __holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +static constexpr auto&& __generic_get(_Vp&& __v) { + return __holds_alternative<_Ip>(__v) + ? __variant_access::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v)) + .__get_value() + : throw bad_variant_access{}; +} + +template +constexpr variant_alternative_t<_Ip, variant<_Types...>>& get( + variant<_Types...>& __v) { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get<_Ip>(__v); +} + +template +constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get( + variant<_Types...>&& __v) { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get<_Ip>(_VSTD::move(__v)); +} + +template +constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get( + const variant<_Types...>& __v) { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get<_Ip>(__v); +} + +template +constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get( + const variant<_Types...>&& __v) { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get<_Ip>(_VSTD::move(__v)); +} + +template +constexpr _Tp& get(variant<_Types...>& __v) { + static_assert(!is_void_v<_Tp>); + return _VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +constexpr _Tp&& get(variant<_Types...>&& __v) { + static_assert(!is_void_v<_Tp>); + return _VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>( + _VSTD::move(__v)); +} + +template +constexpr const _Tp& get(const variant<_Types...>& __v) { + static_assert(!is_void_v<_Tp>); + return _VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +constexpr const _Tp&& get(const variant<_Types...>&& __v) { + static_assert(!is_void_v<_Tp>); + return _VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>( + _VSTD::move(__v)); +} + +template +constexpr auto* __generic_get_if(_Vp* __v) noexcept { + return __v && __holds_alternative<_Ip>(*__v) + ? _VSTD::addressof( + __variant_access::__get_alt<_Ip>(*__v).__get_value()) + : nullptr; +} + +template +constexpr add_pointer_t>> +get_if(variant<_Types...>* __v) noexcept { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get_if<_Ip>(__v); +} + +template +constexpr add_pointer_t>> +get_if(const variant<_Types...>* __v) noexcept { + static_assert(_Ip < sizeof...(_Types)); + static_assert(!is_void_v>>); + return __generic_get_if<_Ip>(__v); +} + +template +constexpr add_pointer_t<_Tp> +get_if(variant<_Types...>* __v) noexcept { + static_assert(!is_void_v<_Tp>); + return _VSTD::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +constexpr add_pointer_t +get_if(const variant<_Types...>* __v) noexcept { + static_assert(!is_void_v<_Tp>); + return _VSTD::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +constexpr bool operator==(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__lhs.index() != __rhs.index()) return false; + if (__lhs.valueless_by_exception()) return true; + return __variant_visitation::__visit_value_at( + __lhs.index(), equal_to<>{}, __lhs, __rhs); +} + +template +constexpr bool operator!=(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__lhs.index() != __rhs.index()) return true; + if (__lhs.valueless_by_exception()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), not_equal_to<>{}, __lhs, __rhs); +} + +template +constexpr bool operator<(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__rhs.valueless_by_exception()) return false; + if (__lhs.valueless_by_exception()) return true; + if (__lhs.index() < __rhs.index()) return true; + if (__lhs.index() > __rhs.index()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), less<>{}, __lhs, __rhs); +} + +template +constexpr bool operator>(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__lhs.valueless_by_exception()) return false; + if (__rhs.valueless_by_exception()) return true; + if (__lhs.index() > __rhs.index()) return true; + if (__lhs.index() < __rhs.index()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), greater<>{}, __lhs, __rhs); +} + +template +constexpr bool operator<=(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__lhs.valueless_by_exception()) return true; + if (__rhs.valueless_by_exception()) return false; + if (__lhs.index() < __rhs.index()) return true; + if (__lhs.index() > __rhs.index()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), less_equal<>{}, __lhs, __rhs); +} + +template +constexpr bool operator>=(const variant<_Types...>& __lhs, + const variant<_Types...>& __rhs) { + if (__rhs.valueless_by_exception()) return true; + if (__lhs.valueless_by_exception()) return false; + if (__lhs.index() > __rhs.index()) return true; + if (__lhs.index() < __rhs.index()) return false; + return __variant_visitation::__visit_value_at( + __lhs.index(), greater_equal<>{}, __lhs, __rhs); +} + +template +constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { + bool __results[] = {__vs.valueless_by_exception()...}; + for (bool __result : __results) { + if (__result) { + throw bad_variant_access{}; + } + } + return __variant_visitation::__visit_value( + _VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); +} + +struct _LIBCPP_TYPE_VIS_ONLY monostate {}; + +constexpr bool operator<(monostate, monostate) noexcept { return false; } +constexpr bool operator>(monostate, monostate) noexcept { return false; } +constexpr bool operator<=(monostate, monostate) noexcept { return true; } +constexpr bool operator>=(monostate, monostate) noexcept { return true; } +constexpr bool operator==(monostate, monostate) noexcept { return true; } +constexpr bool operator!=(monostate, monostate) noexcept { return false; } + +template +void swap(variant<_Types...> &__lhs, + variant<_Types...> &__rhs) noexcept(noexcept(__lhs.swap(__rhs))) { + __lhs.swap(__rhs); +} + +template +struct _LIBCPP_TYPE_VIS_ONLY hash> { + using argument_type = variant<_Types...>; + using result_type = size_t; + + result_type operator()(const argument_type& __v) const { + return __v.valueless_by_exception() + ? variant_npos + : __variant_visitation::__visit_alt( + [](const auto& __alt) { + using __alt_type = decay_t; + using __value_type = typename __alt_type::__value_type; + return hash<__value_type>{}(__alt.__get_value()); + }, + __v); + } +}; + +template <> +struct _LIBCPP_TYPE_VIS_ONLY hash { + using argument_type = monostate; + using result_type = size_t; + + result_type operator()(const argument_type&) const { return 0; } +}; + +#endif // _LIBCPP_STD_VER > 14 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_VARIANT Index: src/variant.cpp =================================================================== --- /dev/null +++ src/variant.cpp @@ -0,0 +1,18 @@ +//===------------------------ variant.cpp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "variant" + +namespace std { + +const char* bad_variant_access::what() const noexcept { + return "bad_variant_access"; +} + +} // namespace std Index: test/std/utilities/variant/variant.hash/hash.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.hash/hash.pass.cpp @@ -0,0 +1,94 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template struct hash>; +// template <> struct hash; + +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +#ifndef TEST_HAS_NO_EXCEPTIONS +namespace std { + template <> + struct hash<::MakeEmptyT> { + size_t operator()(::MakeEmptyT const&) const { assert(false); return 0; } + }; +} +#endif + +void test_hash_variant() +{ + { + using V = std::variant; + using H = std::hash; + const V v(42); + V v2(100); + const H h{}; + assert(h(v) == std::hash{}(42)); + assert(h(v2) == std::hash{}(100)); + { + ASSERT_SAME_TYPE(decltype(h(v)), std::size_t); + static_assert(std::is_copy_constructible::value, ""); + } + } + { + using V = std::variant; + using H = std::hash; + const char* str = "hello"; + const V v0; + const V v1(42); + V v2(100l); + V v3(str); + const H h{}; + assert(h(v0) == std::hash{}(std::monostate{})); + assert(h(v1) == std::hash{}(42)); + assert(h(v2) == std::hash{}(100)); + assert(h(v3) == std::hash{}(str)); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + using H = std::hash; + V v; makeEmpty(v); + V v2; makeEmpty(v2); + const H h{}; + assert(h(v) == h(v2)); + } +#endif +} + +void test_hash_monostate() +{ + using H = std::hash; + const H h{}; + std::monostate m1{}; + const std::monostate m2{}; + assert(h(m1) == h(m1)); + assert(h(m2) == h(m2)); + assert(h(m1) == h(m2)); + { + ASSERT_SAME_TYPE(decltype(h(m1)), std::size_t); + static_assert(std::is_copy_constructible::value, ""); + } +} + +int main() +{ + test_hash_variant(); + test_hash_monostate(); +} Index: test/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp @@ -0,0 +1,57 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template struct variant_alternative; // undefined +// template struct variant_alternative; +// template struct variant_alternative; +// template struct variant_alternative; +// template +// using variant_alternative_t = typename variant_alternative::type; +// +// template +// struct variant_alternative>; + +#include +#include + +template +void test() { + static_assert(std::is_same_v< + typename std::variant_alternative::type, E>, ""); + static_assert(std::is_same_v< + typename std::variant_alternative::type, const E>, ""); + static_assert(std::is_same_v< + typename std::variant_alternative::type, volatile E>, ""); + static_assert(std::is_same_v< + typename std::variant_alternative::type, const volatile E>, ""); + static_assert(std::is_same_v< + std::variant_alternative_t, E>, ""); + static_assert(std::is_same_v< + std::variant_alternative_t, const E>, ""); + static_assert(std::is_same_v< + std::variant_alternative_t, volatile E>, ""); + static_assert(std::is_same_v< + std::variant_alternative_t, const volatile E>, ""); +} + +int main() +{ + test, 0, void>(); + using V = std::variant; + test(); + test(); + test(); + test(); + test(); +} Index: test/std/utilities/variant/variant.helpers/variant_size.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.helpers/variant_size.pass.cpp @@ -0,0 +1,44 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template struct variant_size; // undefined +// template struct variant_size; +// template struct variant_size; +// template struct variant_size; +// template constexpr size_t variant_size_v +// = variant_size::value; + +#include +#include + +template +void test() { + static_assert(std::variant_size::value == E, ""); + static_assert(std::variant_size::value == E, ""); + static_assert(std::variant_size::value == E, ""); + static_assert(std::variant_size::value == E, ""); + static_assert(std::variant_size_v == E, ""); + static_assert(std::variant_size_v == E, ""); + static_assert(std::variant_size_v == E, ""); + static_assert(std::variant_size_v == E, ""); + static_assert(std::is_base_of, + std::variant_size>::value, ""); +}; + +int main() +{ + test, 0>(); + test, 1>(); + test, 4>(); +} Index: test/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp @@ -0,0 +1,38 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +/* + + class bad_variant_access : public exception { +public: + bad_variant_access() noexcept; + virtual const char* what() const noexcept; +}; + +*/ + +#include +#include +#include +#include + +int main() +{ + static_assert(std::is_base_of::value, ""); + static_assert(noexcept(std::bad_variant_access{}), "must be noexcept"); + static_assert(noexcept(std::bad_variant_access{}.what()), "must be noexcept"); + std::bad_variant_access ex; + assert(ex.what()); + +} Index: test/std/utilities/variant/variant.general/nothing_to_do.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.general/nothing_to_do.pass.cpp @@ -0,0 +1,13 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main() +{ +} Index: test/std/utilities/variant/variant.get/get_if_index.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.get/get_if_index.pass.cpp @@ -0,0 +1,133 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template +// constexpr add_pointer_t>> +// get_if(variant* v) noexcept; +// template +// constexpr add_pointer_t>> +// get_if(const variant* v) noexcept; + +#include +#include +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +void test_const_get_if() { + { + using V = std::variant; + constexpr const V* v = nullptr; + static_assert(std::get_if<0>(v) == nullptr, ""); + } + { + using V = std::variant; + constexpr V v(42); + ASSERT_NOEXCEPT(std::get_if<0>(&v)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), int const*); + static_assert(*std::get_if<0>(&v) == 42, ""); + static_assert(std::get_if<1>(&v) == nullptr, ""); + } + { + using V = std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(std::get_if<1>(&v)), long const*); + static_assert(*std::get_if<1>(&v) == 42, ""); + static_assert(std::get_if<0>(&v) == nullptr, ""); + } + // FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), const int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } +#endif +} + +void test_get_if() +{ + { + using V = std::variant; + V* v = nullptr; + assert(std::get_if<0>(v) == nullptr); + } + { + using V = std::variant; + V v(42); + ASSERT_NOEXCEPT(std::get_if<0>(std::addressof(v))); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(*std::get_if<0>(std::addressof(v)) == 42); + assert(std::get_if<1>(std::addressof(v)) == nullptr); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get_if<1>(std::addressof(v))), long*); + assert(*std::get_if<1>(std::addressof(v)) == 42); + assert(std::get_if<0>(std::addressof(v)) == nullptr); + } + // FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), const int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if<0>(std::addressof(v))), const int*); + assert(std::get_if<0>(std::addressof(v)) == &x); + } +#endif +} + +int main() +{ + test_const_get_if(); + test_get_if(); +} Index: test/std/utilities/variant/variant.get/get_if_type.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.get/get_if_type.pass.cpp @@ -0,0 +1,131 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template +// constexpr add_pointer_t get_if(variant* v) noexcept; +// template +// constexpr add_pointer_t get_if(const variant* v) noexcept; + +#include +#include +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +void test_const_get_if() { + { + using V = std::variant; + constexpr const V* v = nullptr; + static_assert(std::get_if(v) == nullptr, ""); + } + { + using V = std::variant; + constexpr V v(42); + ASSERT_NOEXCEPT(std::get_if(&v)); + ASSERT_SAME_TYPE(decltype(std::get_if(&v)), int const*); + static_assert(*std::get_if(&v) == 42, ""); + static_assert(std::get_if(&v) == nullptr, ""); + } + { + using V = std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(std::get_if(&v)), long const*); + static_assert(*std::get_if(&v) == 42, ""); + static_assert(std::get_if(&v) == nullptr, ""); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), const int*); + assert(std::get_if(std::addressof(v)) == &x); + } +#endif +} + +void test_get_if() +{ + { + using V = std::variant; + V* v = nullptr; + assert(std::get_if(v) == nullptr); + } + { + using V = std::variant; + V v(42); + ASSERT_NOEXCEPT(std::get_if(std::addressof(v))); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(*std::get_if(std::addressof(v)) == 42); + assert(std::get_if(std::addressof(v)) == nullptr); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), long*); + assert(*std::get_if(std::addressof(v)) == 42); + assert(std::get_if(std::addressof(v)) == nullptr); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), const int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), int*); + assert(std::get_if(std::addressof(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get_if(std::addressof(v))), const int*); + assert(std::get_if(std::addressof(v)) == &x); + } +#endif +} + +int main() +{ + test_const_get_if(); + test_get_if(); +} Index: test/std/utilities/variant/variant.get/get_index.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.get/get_index.pass.cpp @@ -0,0 +1,269 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template +// constexpr variant_alternative_t>& get(variant& v); +// template +// constexpr variant_alternative_t>&& get(variant&& v); +// template +// constexpr variant_alternative_t> const& get(const variant& v); +// template +// constexpr variant_alternative_t> const&& get(const variant&& v); + +#include +#include +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +void test_const_lvalue_get() { + { + using V = std::variant; + constexpr V v(42); + //ASSERT_NOT_NOEXCEPT(std::get<0>(v)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int const&); + static_assert(std::get<0>(v) == 42, ""); + } + { + using V = std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(std::get<1>(v)), long const&); + static_assert(std::get<1>(v) == 42, ""); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int&); + assert(&std::get<0>(v) == &x); + } +#endif +} + +void test_lvalue_get() +{ + { + using V = std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(std::get<0>(v)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(std::get<0>(v) == 42); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get<1>(v)), long&); + assert(std::get<1>(v) == 42); + } + // FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int&); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int&); + assert(&std::get<0>(v) == &x); + } +#endif +} + + +void test_rvalue_get() +{ + { + using V = std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(std::get<0>(std::move(v))); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&&); + assert(std::get<0>(std::move(v)) == 42); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get<1>(std::move(v))), long&&); + assert(std::get<1>(std::move(v)) == 42); + } + // FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&); + assert(&std::get<0>(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&); + assert(&std::get<0>(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&&); + int&& xref = std::get<0>(std::move(v)); + assert(&xref == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&&); + const int&& xref = std::get<0>(std::move(v)); + assert(&xref == &x); + } +#endif +} + + +void test_const_rvalue_get() +{ + { + using V = std::variant; + const V v(42); + ASSERT_NOT_NOEXCEPT(std::get<0>(std::move(v))); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&&); + assert(std::get<0>(std::move(v)) == 42); + } + { + using V = std::variant; + const V v(42l); + ASSERT_SAME_TYPE(decltype(std::get<1>(std::move(v))), const long&&); + assert(std::get<1>(std::move(v)) == 42); + } + // FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&); + assert(&std::get<0>(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&); + assert(&std::get<0>(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int&&); + int&& xref = std::get<0>(std::move(v)); + assert(&xref == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int&&); + const int&& xref = std::get<0>(std::move(v)); + assert(&xref == &x); + } +#endif +} + +template +using Idx = std::integral_constant; + +void test_throws_for_all_value_categories() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + V v0(42); + const V& cv0 = v0; + assert(v0.index() == 0); + V v1(42l); + const V& cv1 = v1; + assert(v1.index() == 1); + std::integral_constant zero; + std::integral_constant one; + auto test = [](auto idx, auto&& v) { + using Idx = decltype(idx); + try { + std::get(std::forward(v)); + } catch (std::bad_variant_access const&) { + return true; + } catch (...) { /* ... */ } + return false; + }; + { // lvalue test cases + assert(test(one, v0)); + assert(test(zero, v1)); + } + { // const lvalue test cases + assert(test(one, cv0)); + assert(test(zero, cv1)); + } + { // rvalue test cases + assert(test(one, std::move(v0))); + assert(test(zero, std::move(v1))); + } + { // const rvalue test cases + assert(test(one, std::move(cv0))); + assert(test(zero, std::move(cv1))); + } +#endif +} + +int main() +{ + test_const_lvalue_get(); + test_lvalue_get(); + test_rvalue_get(); + test_const_rvalue_get(); + test_throws_for_all_value_categories(); +} Index: test/std/utilities/variant/variant.get/get_type.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.get/get_type.pass.cpp @@ -0,0 +1,264 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template constexpr T& get(variant& v); +// template constexpr T&& get(variant&& v); +// template constexpr const T& get(const variant& v); +// template constexpr const T&& get(const variant&& v); + +#include +#include +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +void test_const_lvalue_get() { + { + using V = std::variant; + constexpr V v(42); + //ASSERT_NOT_NOEXCEPT(std::get(v)); + ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int const&); + static_assert(std::get(v) == 42, ""); + } + { + using V = std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(std::get(v)), long const&); + static_assert(std::get(v) == 42, ""); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(v)), const int&); + assert(&std::get(v) == &x); + } +#endif +} + +void test_lvalue_get() +{ + { + using V = std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(std::get(v)); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(std::get(v) == 42); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get(v)), long&); + assert(std::get(v) == 42); + } + // FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get(v)), const int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(v)), int&); + assert(&std::get(v) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(v)), const int&); + assert(&std::get(v) == &x); + } +#endif +} + + +void test_rvalue_get() +{ + { + using V = std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(std::get(std::move(v))); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&&); + assert(std::get(std::move(v)) == 42); + } + { + using V = std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), long&&); + assert(std::get(std::move(v)) == 42); + } + // FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&); + assert(&std::get(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&); + assert(&std::get(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&&); + int&& xref = std::get(std::move(v)); + assert(&xref == &x); + } + { + using V = std::variant; + int x = 42; + V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&&); + const int&& xref = std::get(std::move(v)); + assert(&xref == &x); + } +#endif +} + + +void test_const_rvalue_get() +{ + { + using V = std::variant; + const V v(42); + ASSERT_NOT_NOEXCEPT(std::get(std::move(v))); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&&); + assert(std::get(std::move(v)) == 42); + } + { + using V = std::variant; + const V v(42l); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const long&&); + assert(std::get(std::move(v)) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&); + assert(&std::get(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&); + assert(&std::get(std::move(v)) == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), int&&); + int&& xref = std::get(std::move(v)); + assert(&xref == &x); + } + { + using V = std::variant; + int x = 42; + const V v(std::move(x)); + ASSERT_SAME_TYPE(decltype(std::get(std::move(v))), const int&&); + const int&& xref = std::get(std::move(v)); + assert(&xref == &x); + } +#endif +} + +template struct identity { using type = Tp; }; + +void test_throws_for_all_value_categories() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + V v0(42); + const V& cv0 = v0; + assert(v0.index() == 0); + V v1(42l); + const V& cv1 = v1; + assert(v1.index() == 1); + identity zero; + identity one; + auto test = [](auto idx, auto&& v) { + using Idx = decltype(idx); + try { + std::get(std::forward(v)); + } catch (std::bad_variant_access const&) { + return true; + } catch (...) { /* ... */ } + return false; + }; + { // lvalue test cases + assert(test(one, v0)); + assert(test(zero, v1)); + } + { // const lvalue test cases + assert(test(one, cv0)); + assert(test(zero, cv1)); + } + { // rvalue test cases + assert(test(one, std::move(v0))); + assert(test(zero, std::move(v1))); + } + { // const rvalue test cases + assert(test(one, std::move(cv0))); + assert(test(zero, std::move(cv1))); + } +#endif +} + +int main() +{ + test_const_lvalue_get(); + test_lvalue_get(); + test_rvalue_get(); + test_const_rvalue_get(); + test_throws_for_all_value_categories(); +} Index: test/std/utilities/variant/variant.get/holds_alternative.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.get/holds_alternative.pass.cpp @@ -0,0 +1,38 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template +// constexpr bool holds_alternative(const variant& v) noexcept; + +#include + +int main() +{ + { + using V = std::variant; + constexpr V v; + static_assert(std::holds_alternative(v), ""); + } + { + using V = std::variant; + constexpr V v; + static_assert(std::holds_alternative(v), ""); + static_assert(!std::holds_alternative(v), ""); + } + { // noexcept test + using V = std::variant; + const V v; + static_assert(noexcept(std::holds_alternative(v)), "must be noexcept"); + } +} Index: test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp @@ -0,0 +1,55 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// constexpr bool operator<(monostate, monostate) noexcept { return false; } +// constexpr bool operator>(monostate, monostate) noexcept { return false; } +// constexpr bool operator<=(monostate, monostate) noexcept { return true; } +// constexpr bool operator>=(monostate, monostate) noexcept { return true; } +// constexpr bool operator==(monostate, monostate) noexcept { return true; } +// constexpr bool operator!=(monostate, monostate) noexcept { return false; } + +#include +#include +#include + +int main() +{ + using M = std::monostate; + constexpr M m1{}; + constexpr M m2{}; + { + static_assert((m1 < m2) == false, ""); + static_assert(noexcept(m1 < m2), ""); + } + { + static_assert((m1 > m2) == false, ""); + static_assert(noexcept(m1 > m2), ""); + } + { + static_assert((m1 <= m2) == true, ""); + static_assert(noexcept(m1 <= m2), ""); + } + { + static_assert((m1 >= m2) == true, ""); + static_assert(noexcept(m1 >= m2), ""); + } + { + static_assert((m1 == m2) == true, ""); + static_assert(noexcept(m1 == m2), ""); + } + { + static_assert((m1 != m2) == false, ""); + static_assert(noexcept(m1 != m2), ""); + } +} Index: test/std/utilities/variant/variant.monostate/monostate.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.monostate/monostate.pass.cpp @@ -0,0 +1,31 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// struct monostate {}; + + +#include +#include +#include + +int main() +{ + using M = std::monostate; + static_assert(std::is_trivially_default_constructible::value, ""); + static_assert(std::is_trivially_copy_constructible::value, ""); + static_assert(std::is_trivially_copy_assignable::value, ""); + static_assert(std::is_trivially_destructible::value, ""); + constexpr M m{}; + ((void)m); +} Index: test/std/utilities/variant/variant.relops/relops.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.relops/relops.pass.cpp @@ -0,0 +1,209 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template +// constexpr bool +// operator==(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator!=(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator<(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator>(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator<=(variant const&, variant const&) noexcept; +// +// template +// constexpr bool +// operator>=(variant const&, variant const&) noexcept; + +#include +#include +#include + +#include "test_macros.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + MakeEmptyT() = default; + MakeEmptyT(MakeEmptyT&&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } +}; +inline bool operator==(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator!=(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator< (MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator<=(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator>(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } +inline bool operator>=(MakeEmptyT const&, MakeEmptyT const&) { assert(false); } + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place_type); + try { + v = std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +void test_equality() +{ + { + using V = std::variant; + constexpr V v1(42); + constexpr V v2(42); + static_assert(v1 == v2, ""); + static_assert(v2 == v1, ""); + static_assert(!(v1 != v2), ""); + static_assert(!(v2 != v1), ""); + } + { + using V = std::variant; + constexpr V v1(42); + constexpr V v2(43); + static_assert(!(v1 == v2), ""); + static_assert(!(v2 == v1), ""); + static_assert(v1 != v2, ""); + static_assert(v2 != v1, ""); + } + { + using V = std::variant; + constexpr V v1(42); + constexpr V v2(42l); + static_assert(!(v1 == v2), ""); + static_assert(!(v2 == v1), ""); + static_assert(v1 != v2, ""); + static_assert(v2 != v1, ""); + } + { + using V = std::variant; + constexpr V v1(42l); + constexpr V v2(42l); + static_assert(v1 == v2, ""); + static_assert(v2 == v1, ""); + static_assert(!(v1 != v2), ""); + static_assert(!(v2 != v1), ""); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v1; + V v2; makeEmpty(v2); + assert(!(v1 == v2)); + assert(!(v2 == v1)); + assert(v1 != v2); + assert(v2 != v1); + } + { + using V = std::variant; + V v1; makeEmpty(v1); + V v2; + assert(!(v1 == v2)); + assert(!(v2 == v1)); + assert(v1 != v2); + assert(v2 != v1); + } + { + using V = std::variant; + V v1; makeEmpty(v1); + V v2; makeEmpty(v2); + assert(v1 == v2); + assert(v2 == v1); + assert(!(v1 != v2)); + assert(!(v2 != v1)); + } +#endif +} + +template +constexpr bool test_less(Var const& l, Var const& r, bool expect_less, + bool expect_greater) { + return ((l < r) == expect_less) + && (!(l >= r) == expect_less) + && ((l > r) == expect_greater) + && (!(l <= r) == expect_greater); +} + +void test_relational() +{ + { // same index, same value + using V = std::variant; + constexpr V v1(1); + constexpr V v2(1); + static_assert(test_less(v1, v2, false, false), ""); + } + { // same index, value < other_value + using V = std::variant; + constexpr V v1(0); + constexpr V v2(1); + static_assert(test_less(v1, v2, true, false), ""); + } + { // same index, value > other_value + using V = std::variant; + constexpr V v1(1); + constexpr V v2(0); + static_assert(test_less(v1, v2, false, true), ""); + } + { // LHS.index() < RHS.index() + using V = std::variant; + constexpr V v1(0); + constexpr V v2(0l); + static_assert(test_less(v1, v2, true, false), ""); + } + { // LHS.index() > RHS.index() + using V = std::variant; + constexpr V v1(0l); + constexpr V v2(0); + static_assert(test_less(v1, v2, false, true), ""); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { // LHS.index() < RHS.index(), RHS is empty + using V = std::variant; + V v1; + V v2; makeEmpty(v2); + assert(test_less(v1, v2, false, true)); + } + { // LHS.index() > RHS.index(), LHS is empty + using V = std::variant; + V v1; makeEmpty(v1); + V v2; + assert(test_less(v1, v2, true, false)); + } + { // LHS.index() == RHS.index(), LHS and RHS are empty + using V = std::variant; + V v1; makeEmpty(v1); + V v2; makeEmpty(v2); + assert(test_less(v1, v2, false, false)); + } +#endif +} + +int main() { + test_equality(); + test_relational(); +} Index: test/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp @@ -0,0 +1,22 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// constexpr size_t variant_npos = -1; + +#include + +int main() +{ + static_assert(std::variant_npos == static_cast(-1), ""); +} Index: test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -0,0 +1,227 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template +// variant& operator=(T&&) noexcept(see below); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +namespace MetaHelpers { + +struct Dummy { + Dummy() = default; +}; + +struct ThrowsCtorT { + ThrowsCtorT(int) noexcept(false) {} + ThrowsCtorT& operator=(int) noexcept { return *this; } +}; + +struct ThrowsAssignT { + ThrowsAssignT(int) noexcept {} + ThrowsAssignT& operator=(int) noexcept(false) { return *this; } +}; + +struct NoThrowT { + NoThrowT(int) noexcept {} + NoThrowT& operator=(int) noexcept { return *this; } +}; + +} // namespace MetaHelpers + +namespace RuntimeHelpers { +#ifndef TEST_HAS_NO_EXCEPTIONS + +struct ThrowsCtorT { + int value; + ThrowsCtorT() : value(0) {} + ThrowsCtorT(int) noexcept(false) { throw 42; } + ThrowsCtorT& operator=(int v) noexcept { value = v; return *this; } +}; + +struct ThrowsAssignT { + int value; + ThrowsAssignT() : value(0) {} + ThrowsAssignT(int v) noexcept : value(v) {} + ThrowsAssignT& operator=(int) noexcept(false) { throw 42; } +}; + +struct NoThrowT { + int value; + NoThrowT() : value(0) {} + NoThrowT(int v) noexcept : value(v) {} + NoThrowT& operator=(int v) noexcept { value = v; return *this; } +}; + +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) +} // namespace RuntimeHelpers + +void test_T_assignment_noexcept() { + using namespace MetaHelpers; + { + using V = std::variant; + static_assert(std::is_nothrow_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_assignable::value, ""); + } +} + +void test_T_assignment_sfinae() { + { + using V = std::variant; + static_assert(!std::is_assignable::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_assignable::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_assignable::value, "no matching operator="); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + static_assert(!std::is_assignable::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_assignable::value, "ambiguous"); + } +#endif +} + +void test_T_assignment_basic() +{ + { + std::variant v(43); + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v) == 42); + } + { + std::variant v(43l); + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v) == 42); + v = 43l; + assert(v.index() == 1); + assert(std::get<1>(v) == 43); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + int x = 42; + V v(43l); + v = x; + assert(v.index() == 0); + assert(&std::get<0>(v) == &x); + v = std::move(x); + assert(v.index() == 1); + assert(&std::get<1>(v) == &x); + // 'long' is selected by FUN(int const&) since 'int const&' cannot bind + // to 'int&'. + int const& cx = x; + v = cx; + assert(v.index() == 2); + assert(std::get<2>(v) == 42); + } +#endif +} + +void test_T_assignment_performs_construction() +{ +using namespace RuntimeHelpers; +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v(std::in_place_type, "hello"); + try { + v = 42; + } catch (...) { /* ... */ } + assert(v.valueless_by_exception()); + } + { + using V = std::variant; + V v(std::in_place_type, "hello"); + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v).value == 42); + } +#endif +} + +void test_T_assignment_performs_assignment() +{ + using namespace RuntimeHelpers; +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v; + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v).value == 42); + } + { + using V = std::variant; + V v; + v = 42; + assert(v.index() == 0); + assert(std::get<0>(v).value == 42); + } + { + using V = std::variant; + V v(100); + try { + v = 42; + assert(false); + } catch(...) { /* ... */ } + assert(v.index() == 0); + assert(std::get<0>(v).value == 100); + } + { + using V = std::variant; + V v(100); + try { + v = 42; + assert(false); + } catch(...) { /* ... */ } + assert(v.index() == 1); + assert(std::get<1>(v).value == 100); + } +#endif +} + +int main() +{ + test_T_assignment_basic(); + test_T_assignment_performs_construction(); + test_T_assignment_performs_assignment(); + test_T_assignment_noexcept(); + test_T_assignment_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp @@ -0,0 +1,386 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// variant& operator=(variant const&); + + +#include +#include +#include +#include + +#include "test_macros.h" + +struct NoCopy { + NoCopy(NoCopy const&) = delete; + NoCopy& operator=(NoCopy const&) = default; +}; + +struct NothrowCopy { + NothrowCopy(NothrowCopy const&) noexcept = default; + NothrowCopy& operator=(NothrowCopy const&) noexcept = default; +}; + +struct CopyOnly { + CopyOnly(CopyOnly const&) = default; + CopyOnly(CopyOnly&&) = delete; + CopyOnly& operator=(CopyOnly const&) = default; + CopyOnly& operator=(CopyOnly&&) = delete; +}; + +struct MoveOnly { + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; + MoveOnly& operator=(MoveOnly const&) = default; +}; + +struct MoveOnlyNT { + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&&) {} + MoveOnlyNT& operator=(MoveOnlyNT const&) = default; +}; + +struct CopyAssign { + static int alive; + static int copy_construct; + static int copy_assign; + static int move_construct; + static int move_assign; + static void reset() { + copy_construct = copy_assign = move_construct = move_assign = alive = 0; + } + CopyAssign(int v) : value(v) { ++alive; } + CopyAssign(CopyAssign const& o) : value(o.value) { ++alive; ++copy_construct; } + CopyAssign(CopyAssign&& o) : value(o.value) { o.value = -1; ++alive; ++move_construct; } + CopyAssign& operator=(CopyAssign const& o) { value = o.value; ++copy_assign; return *this; } + CopyAssign& operator=(CopyAssign&& o) { value = o.value; o.value = -1; ++move_assign; return *this; } + ~CopyAssign() { --alive; } + int value; +}; + +int CopyAssign::alive = 0; +int CopyAssign::copy_construct = 0; +int CopyAssign::copy_assign = 0; +int CopyAssign::move_construct = 0; +int CopyAssign::move_assign = 0; + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct CopyThrows { + CopyThrows() = default; + CopyThrows(CopyThrows const&) { throw 42; } + CopyThrows& operator=(CopyThrows const&) { throw 42; } +}; + +struct MoveThrows { + static int alive; + MoveThrows() { ++alive; } + MoveThrows(MoveThrows const&) {++alive;} + MoveThrows(MoveThrows&&) { throw 42; } + MoveThrows& operator=(MoveThrows const&) { return *this; } + MoveThrows& operator=(MoveThrows&&) { throw 42; } + ~MoveThrows() { --alive; } +}; + +int MoveThrows::alive = 0; + +struct MakeEmptyT { + static int alive; + MakeEmptyT() { ++alive; } + MakeEmptyT(MakeEmptyT const&) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + MakeEmptyT(MakeEmptyT &&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT const&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place_type); + try { + v = v2; + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +void test_copy_assignment_not_noexcept() { + { + using V = std::variant; + static_assert(!std::is_nothrow_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_copy_assignable::value, ""); + } +} + +void test_copy_assignment_sfinae() { + { + using V = std::variant; + static_assert(std::is_copy_assignable::value, ""); + } + { + // variant only provides copy assignment when beth the copy and move + // constructors are well formed + using V = std::variant; + static_assert(!std::is_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_assignable::value, ""); + } +} + +void test_copy_assignment_empty_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_index<0>); makeEmpty(v1); + V v2(std::in_place_index<0>); makeEmpty(v2); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } +#endif +} + +void test_copy_assignment_non_empty_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<0>); makeEmpty(v2); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } + { + using V = std::variant; + V v1(std::in_place_index<2>, "hello"); + V v2(std::in_place_index<0>); makeEmpty(v2); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } +#endif +} + + +void test_copy_assignment_empty_non_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_index<0>); makeEmpty(v1); + V v2(std::in_place_index<0>, 42); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(std::get<0>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place_index<0>); makeEmpty(v1); + V v2(std::in_place_type, "hello"); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + } +#endif +} + +void test_copy_assignment_same_index() +{ + { + using V = std::variant; + V v1(43); + V v2(42); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(std::get<0>(v1) == 42); + } + { + using V = std::variant; + V v1(43l); + V v2(42l); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place_type, 43); + V v2(std::in_place_type, 42); + CopyAssign::reset(); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1).value == 42); + assert(CopyAssign::copy_construct == 0); + assert(CopyAssign::move_construct == 0); + assert(CopyAssign::copy_assign == 1); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_type); + MET& mref = std::get<1>(v1); + V v2(std::in_place_type); + try { + v1 = v2; + assert(false); + } catch (...) { + } + assert(v1.index() == 1); + assert(&std::get<1>(v1) == &mref); + } +#endif +} + +void test_copy_assignment_different_index() +{ + { + using V = std::variant; + V v1(43); + V v2(42l); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1) == 42); + } + { + using V = std::variant; + CopyAssign::reset(); + V v1(std::in_place_type, 43); + V v2(std::in_place_type, 42); + assert(CopyAssign::copy_construct == 0); + assert(CopyAssign::move_construct == 0); + assert(CopyAssign::alive == 1); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1).value == 42); + assert(CopyAssign::alive == 2); + assert(CopyAssign::copy_construct == 1); + assert(CopyAssign::move_construct == 1); + assert(CopyAssign::copy_assign == 0); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + // Test that if copy construction throws then original value is + // unchanged. + using V = std::variant; + V v1(std::in_place_type, "hello"); + V v2(std::in_place_type); + try { + v1 = v2; + assert(false); + } catch (...) { /* ... */ } + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + } + { + // Test that if move construction throws then the variant is left + // valueless by exception. + using V = std::variant; + V v1(std::in_place_type, "hello"); + V v2(std::in_place_type); + assert(MoveThrows::alive == 1); + try { + v1 = v2; + assert(false); + } catch (...) { /* ... */ } + assert(v1.valueless_by_exception()); + assert(v2.index() == 1); + assert(MoveThrows::alive == 1); + } + { + using V = std::variant; + V v1(std::in_place_type); + V v2(std::in_place_type, "hello"); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + assert(v2.index() == 2); + assert(std::get<2>(v2) == "hello"); + } + { + using V = std::variant; + V v1(std::in_place_type); + V v2(std::in_place_type, "hello"); + V& vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + assert(v2.index() == 2); + assert(std::get<2>(v2) == "hello"); + } +#endif +} + +int main() +{ + test_copy_assignment_empty_empty(); + test_copy_assignment_non_empty_empty(); + test_copy_assignment_empty_non_empty(); + test_copy_assignment_same_index(); + test_copy_assignment_different_index(); + test_copy_assignment_sfinae(); + test_copy_assignment_not_noexcept(); +} Index: test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp @@ -0,0 +1,314 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// variant& operator=(variant&&) noexcept(see below); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +struct NoCopy { + NoCopy(NoCopy const&) = delete; + NoCopy& operator=(NoCopy const&) = default; +}; + +struct CopyOnly { + CopyOnly(CopyOnly const&) = default; + CopyOnly(CopyOnly&&) = delete; + CopyOnly& operator=(CopyOnly const&) = default; + CopyOnly& operator=(CopyOnly&&) = delete; +}; + +struct MoveOnly { + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; + MoveOnly& operator=(MoveOnly const&) = delete; + MoveOnly& operator=(MoveOnly&&) = default; +}; + +struct MoveOnlyNT { + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&&) {} + MoveOnlyNT& operator=(MoveOnlyNT const&) = delete; + MoveOnlyNT& operator=(MoveOnlyNT&&) = default; +}; + +struct MoveOnlyOddNothrow { + MoveOnlyOddNothrow(MoveOnlyOddNothrow&&) noexcept(false) {} + MoveOnlyOddNothrow(MoveOnlyOddNothrow const&) = delete; + MoveOnlyOddNothrow& operator=(MoveOnlyOddNothrow&&) noexcept = default; + MoveOnlyOddNothrow& operator=(MoveOnlyOddNothrow const&) = delete; +}; + +struct MoveAssignOnly { + MoveAssignOnly(MoveAssignOnly &&) = delete; + MoveAssignOnly& operator=(MoveAssignOnly&&) = default; +}; + +struct MoveAssign { + static int move_construct; + static int move_assign; + static void reset() { + move_construct = move_assign = 0; + } + MoveAssign(int v) : value(v) {} + MoveAssign(MoveAssign&& o) : value(o.value) { ++move_construct; o.value = -1; } + MoveAssign& operator=(MoveAssign&& o) { value = o.value; ++move_assign; o.value = -1; return *this; } + int value; +}; + +int MoveAssign::move_construct = 0; +int MoveAssign::move_assign = 0; + + +void test_move_assignment_noexcept() { + { + using V = std::variant; + static_assert(std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_move_assignable::value, ""); + } +} + +void test_move_assignment_sfinae() { + { + using V = std::variant; + static_assert(std::is_move_assignable::value, ""); + } + { + // variant only provides move assignment when beth the move and move + // constructors are well formed + using V = std::variant; + static_assert(!std::is_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_move_assignable::value, ""); + } + { + // variant only provides move assignment when the types also provide + // a move constructor. + using V = std::variant; + static_assert(!std::is_move_assignable::value, ""); + } +} + +void test_move_assignment_empty_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_index<0>); makeEmpty(v1); + V v2(std::in_place_index<0>); makeEmpty(v2); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } +#endif +} + +void test_move_assignment_non_empty_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<0>); makeEmpty(v2); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } + { + using V = std::variant; + V v1(std::in_place_index<2>, "hello"); + V v2(std::in_place_index<0>); makeEmpty(v2); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } +#endif +} + + +void test_move_assignment_empty_non_empty() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_index<0>); makeEmpty(v1); + V v2(std::in_place_index<0>, 42); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(std::get<0>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place_index<0>); makeEmpty(v1); + V v2(std::in_place_type, "hello"); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + } +#endif +} + +void test_move_assignment_same_index() +{ + { + using V = std::variant; + V v1(43); + V v2(42); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(std::get<0>(v1) == 42); + } + { + using V = std::variant; + V v1(43l); + V v2(42l); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place_type, 43); + V v2(std::in_place_type, 42); + MoveAssign::reset(); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1).value == 42); + assert(MoveAssign::move_construct == 0); + assert(MoveAssign::move_assign == 1); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_type); + MET& mref = std::get<1>(v1); + V v2(std::in_place_type); + try { + v1 = std::move(v2); + assert(false); + } catch (...) { + } + assert(v1.index() == 1); + assert(&std::get<1>(v1) == &mref); + } +#endif +} + +void test_move_assignment_different_index() +{ + { + using V = std::variant; + V v1(43); + V v2(42l); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1) == 42); + } + { + using V = std::variant; + V v1(std::in_place_type, 43); + V v2(std::in_place_type, 42); + MoveAssign::reset(); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(std::get<1>(v1).value == 42); + assert(MoveAssign::move_construct == 1); + assert(MoveAssign::move_assign == 0); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = std::variant; + V v1(std::in_place_type); + V v2(std::in_place_type); + try { + v1 = std::move(v2); + assert(false); + } catch (...) { + } + assert(v1.valueless_by_exception()); + assert(v1.index() == std::variant_npos); + } + { + using V = std::variant; + V v1(std::in_place_type); + V v2(std::in_place_type, "hello"); + V& vref = (v1 = std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(std::get<2>(v1) == "hello"); + } +#endif +} + +int main() +{ + test_move_assignment_empty_empty(); + test_move_assignment_non_empty_empty(); + test_move_assignment_empty_non_empty(); + test_move_assignment_same_index(); + test_move_assignment_different_index(); + test_move_assignment_sfinae(); + test_move_assignment_noexcept(); +} Index: test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp @@ -0,0 +1,114 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template constexpr variant(T&&) noexcept(see below); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" +#include "variant_test_helpers.hpp" + +struct Dummy { + Dummy() = default; +}; + +struct ThrowsT { + ThrowsT(int) noexcept(false) {} +}; + +struct NoThrowT { + NoThrowT(int) noexcept(true) {} +}; + +void test_T_ctor_noexcept() { + { + using V = std::variant; + static_assert(std::is_nothrow_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_constructible::value, ""); + } +} + +void test_T_ctor_sfinae() { + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "no matching constructor"); + } +#if defined(VARIANT_TEST_REFERENCES) + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambiguous"); + } + { + using V = std::variant; + static_assert(!std::is_constructible::value, "ambiguous"); + } +#endif +} + +void test_T_ctor_basic() +{ + { + constexpr std::variant v(42); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 42, ""); + } + { + constexpr std::variant v(42l); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + static_assert(std::is_convertible::value, "must be implicit"); + int x = 42; + V v(x); + assert(v.index() == 0); + assert(&std::get<0>(v) == &x); + } + { + using V = std::variant; + static_assert(std::is_convertible::value, "must be implicit"); + int x = 42; + V v(std::move(x)); + assert(v.index() == 1); + assert(&std::get<1>(v) == &x); + } +#endif +} + +int main() +{ + test_T_ctor_basic(); + test_T_ctor_noexcept(); + test_T_ctor_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -0,0 +1,151 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// variant(variant const&); + + +#include +#include +#include + +#include "test_macros.h" + +struct NonT { + NonT(int v) : value(v) {} + NonT(NonT const& o) : value(o.value) {} + int value; +}; +static_assert(!std::is_trivially_copy_constructible::value, ""); + + +struct NoCopy { + NoCopy(NoCopy const&) = delete; +}; + +struct MoveOnly { + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; +}; + + +struct MoveOnlyNT { + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&&) {} +}; + + + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + static int alive; + MakeEmptyT() { ++alive; } + MakeEmptyT(MakeEmptyT const&) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + MakeEmptyT(MakeEmptyT &&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT const&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place_type); + try { + v = v2; + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +void test_copy_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_copy_constructible::value, ""); + } +} + +void test_copy_ctor_basic() +{ + { + std::variant v(std::in_place_index<0>, 42); + std::variant v2 = v; + assert(v2.index() == 0); + assert(std::get<0>(v2) == 42); + } + { + std::variant v(std::in_place_index<1>, 42); + std::variant v2 = v; + assert(v2.index() == 1); + assert(std::get<1>(v2) == 42); + } + { + std::variant v(std::in_place_index<0>, 42); + assert(v.index() == 0); + std::variant v2(v); + assert(v2.index() == 0); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place_index<1>, 42); + assert(v.index() == 1); + std::variant v2(v); + assert(v2.index() == 1); + assert(std::get<1>(v2).value == 42); + } +} + +void test_copy_ctor_valueless_by_exception() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + V v1; makeEmpty(v1); + V const& cv1 = v1; + V v(cv1); + assert(v.valueless_by_exception()); +#endif +} + +int main() +{ + test_copy_ctor_basic(); + test_copy_ctor_valueless_by_exception(); + test_copy_ctor_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp @@ -0,0 +1,116 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// constexpr variant() noexcept(see below); + + +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +struct NonDefaultConstructible { + NonDefaultConstructible(int) {} +}; + +struct NotNoexcept { + NotNoexcept() noexcept(false) {} +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct DefaultCtorThrows { + DefaultCtorThrows() { throw 42; } +}; +#endif + +void test_default_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_default_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_default_constructible::value, ""); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + static_assert(!std::is_default_constructible::value, ""); + } +#endif +} + +void test_default_ctor_noexcept() { + { + using V = std::variant; + static_assert(std::is_nothrow_default_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_default_constructible::value, ""); + } +} + +void test_default_ctor_throws() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + try { + V v; + assert(false); + } catch (int const& ex) { + assert(ex == 42); + } catch (...) { + assert(false); + } +#endif +} + +void test_default_ctor_basic() +{ + { + std::variant v; + assert(v.index() == 0); + assert(std::get<0>(v) == 0); + } + { + std::variant v; + assert(v.index() == 0); + assert(std::get<0>(v) == 0); + } + { + using V = std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 0, ""); + } + { + using V = std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 0, ""); + } +} + +int main() +{ + test_default_ctor_basic(); + test_default_ctor_sfinae(); + test_default_ctor_noexcept(); + test_default_ctor_throws(); +} Index: test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_Args.pass.cpp @@ -0,0 +1,101 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template +// constexpr explicit variant(in_place_index_t, Args&&...); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +void test_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // args not convertible to type + using V = std::variant; + static_assert(!std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // index not in variant + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } +} + +void test_ctor_basic() +{ + { + constexpr std::variant v(std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 42, ""); + } + { + constexpr std::variant v(std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + constexpr std::variant v(std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place_index<0>, x); + assert(v.index() == 0); + assert(std::get<0>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place_index<1>, x); + assert(v.index() == 1); + assert(std::get<1>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place_index<2>, x); + assert(v.index() == 2); + assert(std::get<2>(v) == x); + } +} + +int main() +{ + test_ctor_basic(); + test_ctor_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_Args.pass.cpp @@ -0,0 +1,93 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template +// constexpr explicit +// variant(in_place_index_t, initializer_list, Args&&...); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +void test_ctor_sfinae() { + using IL = std::initializer_list; + { // just init list + using V = std::variant; + static_assert(std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // too many arguments + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // too few arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // init list and arguments + using V = std::variant; + static_assert(std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // not constructible from arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } +} + +void test_ctor_basic() +{ + { + constexpr std::variant v(std::in_place_index<0>, {1, 2, 3}); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v).size == 3, ""); + } + { + constexpr std::variant v(std::in_place_index<2>, {1, 2, 3}); + static_assert(v.index() == 2, ""); + static_assert(std::get<2>(v).size == 3, ""); + } + { + constexpr std::variant v(std::in_place_index<1>, {1, 2, 3, 4}, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v).size == 4, ""); + static_assert(std::get<1>(v).value == 42, ""); + } +} + +int main() +{ + test_ctor_basic(); + test_ctor_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_Args.pass.cpp @@ -0,0 +1,106 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template +// constexpr explicit variant(in_place_type_t, Args&&...); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +void test_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = std::variant; + static_assert(std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // duplicate type + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { // args not convertible to type + using V = std::variant; + static_assert(!std::is_constructible, int*>::value, ""); + static_assert(!test_convertible, int*>(), ""); + } + { // type not in variant + using V = std::variant; + static_assert(!std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } +} + +void test_ctor_basic() +{ + { + constexpr std::variant v(std::in_place_type, 42); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v) == 42, ""); + } + { + constexpr std::variant v(std::in_place_type, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + constexpr std::variant v(std::in_place_type, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place_type, x); + assert(v.index() == 0); + assert(std::get<0>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place_type, x); + assert(v.index() == 1); + assert(std::get<1>(v) == x); + } + { + using V = std::variant; + int x = 42; + V v(std::in_place_type, x); + assert(v.index() == 2); + assert(std::get<2>(v) == x); + } +} + +int main() +{ + test_ctor_basic(); + test_ctor_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_Args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_Args.pass.cpp @@ -0,0 +1,95 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template +// constexpr explicit +// variant(in_place_type_t, initializer_list, Args&&...); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_convertible.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +void test_ctor_sfinae() { + using IL = std::initializer_list; + { // just init list + using V = std::variant; + static_assert(std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // too many arguments + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // too few arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // init list and arguments + using V = std::variant; + static_assert(std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } + { // not constructible from arguments + using V = std::variant; + static_assert(!std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // duplicate types in variant + using V = std::variant; + static_assert(!std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), ""); + } +} + +void test_ctor_basic() +{ + { + constexpr std::variant v(std::in_place_type, {1, 2, 3}); + static_assert(v.index() == 0, ""); + static_assert(std::get<0>(v).size == 3, ""); + } + { + constexpr std::variant v(std::in_place_type, {1, 2, 3, 4}, 42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v).size == 4, ""); + static_assert(std::get<1>(v).value == 42, ""); + } + +} + +int main() +{ + test_ctor_basic(); + test_ctor_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp @@ -0,0 +1,185 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// variant(variant&&) noexcept(see below); + + +#include +#include +#include +#include + +#include "test_macros.h" + +struct ThrowsMove { + ThrowsMove(ThrowsMove&&) noexcept(false) {} +}; + +struct NoCopy { + NoCopy(NoCopy const&) = delete; +}; + +struct MoveOnly { + int value; + MoveOnly(int v) : value(v) {} + MoveOnly(MoveOnly const&) = delete; + MoveOnly(MoveOnly&&) = default; +}; + +struct MoveOnlyNT { + int value; + MoveOnlyNT(int v) : value(v) {} + MoveOnlyNT(MoveOnlyNT const&) = delete; + MoveOnlyNT(MoveOnlyNT&& other) : value(other.value) { other.value = -1; } +}; + + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + static int alive; + MakeEmptyT() { ++alive; } + MakeEmptyT(MakeEmptyT const&) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + MakeEmptyT(MakeEmptyT &&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT const&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place_type); + try { + v = v2; + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +void test_move_noexcept() { + { + using V = std::variant; + static_assert(std::is_nothrow_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_nothrow_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_nothrow_move_constructible::value, ""); + } +} + +void test_move_ctor_sfinae() { + { + using V = std::variant; + static_assert(std::is_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_move_constructible::value, ""); + } +} + +void test_move_ctor_basic() +{ + { + std::variant v(std::in_place_index<0>, 42); + std::variant v2 = std::move(v); + assert(v2.index() == 0); + assert(std::get<0>(v2) == 42); + } + { + std::variant v(std::in_place_index<1>, 42); + std::variant v2 = std::move(v); + assert(v2.index() == 1); + assert(std::get<1>(v2) == 42); + } + { + std::variant v(std::in_place_index<0>, 42); + assert(v.index() == 0); + std::variant v2(std::move(v)); + assert(v2.index() == 0); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place_index<1>, 42); + assert(v.index() == 1); + std::variant v2(std::move(v)); + assert(v2.index() == 1); + assert(std::get<1>(v2).value == 42); + } + { + std::variant v(std::in_place_index<0>, 42); + assert(v.index() == 0); + std::variant v2(std::move(v)); + assert(v2.index() == 0); + assert(std::get<0>(v).value == -1); + assert(std::get<0>(v2).value == 42); + } + { + std::variant v(std::in_place_index<1>, 42); + assert(v.index() == 1); + std::variant v2(std::move(v)); + assert(v2.index() == 1); + assert(std::get<1>(v).value == -1); + assert(std::get<1>(v2).value == 42); + } +} + +void test_move_ctor_valueless_by_exception() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + V v1; makeEmpty(v1); + V v(std::move(v1)); + assert(v.valueless_by_exception()); +#endif +} + +int main() +{ + test_move_ctor_basic(); + test_move_ctor_valueless_by_exception(); + test_move_noexcept(); + test_move_ctor_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp @@ -0,0 +1,81 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// ~variant(); + + +#include +#include +#include + +#include "test_macros.h" + + +struct NonTDtor { + static int count; + NonTDtor() = default; + ~NonTDtor() { ++count; } +}; +int NonTDtor::count = 0; +static_assert(!std::is_trivially_destructible::value, ""); + + +struct NonTDtor1 { + static int count; + NonTDtor1() = default; + ~NonTDtor1() { ++count; } +}; +int NonTDtor1::count = 0; +static_assert(!std::is_trivially_destructible::value, ""); + +struct TDtor { + TDtor(TDtor const&) {} // non-trivial copy + ~TDtor() = default; +}; +static_assert(!std::is_trivially_copy_constructible::value, ""); +static_assert(std::is_trivially_destructible::value, ""); + +int main() +{ + { + using V = std::variant; + static_assert(std::is_trivially_destructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_trivially_destructible::value, ""); + { + V v(std::in_place_index<0>); + assert(NonTDtor::count == 0); + assert(NonTDtor1::count == 0); + } + assert(NonTDtor::count == 1); + assert(NonTDtor1::count == 0); + NonTDtor::count = 0; + { + V v(std::in_place_index<1>); + } + assert(NonTDtor::count == 0); + assert(NonTDtor1::count == 0); + { + V v(std::in_place_index<2>); + assert(NonTDtor::count == 0); + assert(NonTDtor1::count == 0); + } + assert(NonTDtor::count == 0); + assert(NonTDtor1::count == 1); + } +} Index: test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp @@ -0,0 +1,135 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template void emplace(Args&&... args); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "archetypes.hpp" +#include "test_convertible.hpp" +#include "variant_test_helpers.hpp" + +template +constexpr auto test_emplace_exists_imp(int) -> decltype(std::declval().template emplace(std::declval()...), true) +{ return true; } + +template +constexpr auto test_emplace_exists_imp(long) -> bool { return false; } + +template +constexpr bool emplace_exists() { return test_emplace_exists_imp(0); } + +void test_emplace_sfinae() { + { + using V = std::variant; + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot construct"); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot construct"); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot construct"); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "too many args"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot default construct ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "not constructible from void*"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "no ctors"); + } +#endif + +} + +void test_basic() { + { + using V = std::variant; + V v(42); + v.emplace<0>(); + assert(std::get<0>(v) == 0); + v.emplace<0>(42); + assert(std::get<0>(v) == 42); + } + { + using V = std::variant; + const int x = 100; + int y = 42; + int z = 43; + V v(std::in_place_index<0>, -1); + // default emplace a value + v.emplace<1>(); + assert(std::get<1>(v) == 0); + v.emplace<2>(&x); + assert(std::get<2>(v) == &x); + // emplace with multiple args + v.emplace<4>(3, 'a'); + assert(std::get<4>(v) == "aaa"); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + const int x = 100; + int y = 42; + int z = 43; + V v(std::in_place_index<0>, -1); + // default emplace a value + v.emplace<1>(); + assert(std::get<1>(v) == 0); + // emplace a reference + v.emplace<2>(x); + assert(&std::get<2>(v) == &x); + // emplace an rvalue reference + v.emplace<3>(std::move(y)); + assert(&std::get<3>(v) == &y); + // re-emplace a new reference over the active member + v.emplace<3>(std::move(z)); + assert(&std::get<3>(v) == &z); + // emplace with multiple args + v.emplace<5>(3, 'a'); + assert(std::get<5>(v) == "aaa"); + } +#endif +} + + +int main() +{ + test_basic(); + test_emplace_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp @@ -0,0 +1,81 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template +// void emplace(initializer_list il,Args&&... args); + + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "archetypes.hpp" +#include "test_convertible.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +template +constexpr auto test_emplace_exists_imp(int) -> decltype(std::declval().template emplace(std::declval()...), true) +{ return true; } + +template +constexpr auto test_emplace_exists_imp(long) -> bool { return false; } + +template +constexpr bool emplace_exists() { return test_emplace_exists_imp(0); } + +void test_emplace_sfinae() { + using V = std::variant; + using IL = std::initializer_list; + static_assert(!emplace_exists(), "no such constructor"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "args don't match"); + static_assert(!emplace_exists(), "too many args"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "args don't match"); + static_assert(!emplace_exists(), "too few args"); + static_assert(!emplace_exists(), "too many args"); +} + +void test_basic() { + using V = std::variant; + V v; + v.emplace<1>({1, 2, 3}); + assert(std::get<1>(v).size == 3); + v.emplace<2>({1, 2, 3, 4}, 42); + assert(std::get<2>(v).size == 4); + assert(std::get<2>(v).value == 42); + v.emplace<1>({1}); + assert(std::get<1>(v).size == 1); +} + +int main() +{ + test_basic(); + test_emplace_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp @@ -0,0 +1,135 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template void emplace(Args&&... args); + + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "archetypes.hpp" +#include "test_convertible.hpp" +#include "variant_test_helpers.hpp" + +template +constexpr auto test_emplace_exists_imp(int) -> decltype(std::declval().template emplace(std::declval()...), true) +{ return true; } + +template +constexpr auto test_emplace_exists_imp(long) -> bool { return false; } + +template +constexpr bool emplace_exists() { return test_emplace_exists_imp(0); } + +void test_emplace_sfinae() { + { + using V = std::variant; + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot construct"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot construct"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot construct"); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + using V = std::variant; + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "too many args"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot default construct ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "not constructible from void*"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "cannot bind ref"); + static_assert(!emplace_exists(), "ambiguous"); + static_assert(!emplace_exists(), "cannot construct void"); +#endif +} + +void test_basic() { + { + using V = std::variant; + V v(42); + v.emplace(); + assert(std::get<0>(v) == 0); + v.emplace(42); + assert(std::get<0>(v) == 42); + } + { + using V = std::variant; + const int x = 100; + int y = 42; + int z = 43; + V v(std::in_place_type, -1); + // default emplace a value + v.emplace(); + assert(std::get<1>(v) == 0); + v.emplace(&x); + assert(std::get<2>(v) == &x); + // emplace with multiple args + v.emplace(3, 'a'); + assert(std::get<4>(v) == "aaa"); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = std::variant; + const int x = 100; + int y = 42; + int z = 43; + V v(std::in_place_index<0>, -1); + // default emplace a value + v.emplace(); + assert(std::get(v) == 0); + // emplace a reference + v.emplace(x); + assert(&std::get(v) == &x); + // emplace an rvalue reference + v.emplace(std::move(y)); + assert(&std::get(v) == &y); + // re-emplace a new reference over the active member + v.emplace(std::move(z)); + assert(&std::get(v) == &z); + // emplace with multiple args + v.emplace(3, 'a'); + assert(std::get(v) == "aaa"); + } +#endif +} + + +int main() +{ + test_basic(); + test_emplace_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp @@ -0,0 +1,80 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// template +// void emplace(initializer_list il,Args&&... args); + + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "archetypes.hpp" +#include "test_convertible.hpp" + +struct InitList { + std::size_t size; + constexpr InitList(std::initializer_list il) : size(il.size()){} +}; + +struct InitListArg { + std::size_t size; + int value; + constexpr InitListArg(std::initializer_list il, int v) : size(il.size()), value(v) {} +}; + +template +constexpr auto test_emplace_exists_imp(int) -> decltype(std::declval().template emplace(std::declval()...), true) +{ return true; } + +template +constexpr auto test_emplace_exists_imp(long) -> bool { return false; } + +template +constexpr bool emplace_exists() { return test_emplace_exists_imp(0); } + +void test_emplace_sfinae() { + using V = std::variant; + using IL = std::initializer_list; + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "args don't match"); + static_assert(!emplace_exists(), "too many args"); + static_assert(emplace_exists(), ""); + static_assert(!emplace_exists(), "args don't match"); + static_assert(!emplace_exists(), "too few args"); + static_assert(!emplace_exists(), "too many args"); +} + +void test_basic() { + using V = std::variant; + V v; + v.emplace({1, 2, 3}); + assert(std::get(v).size == 3); + v.emplace({1, 2, 3, 4}, 42); + assert(std::get(v).size == 4); + assert(std::get(v).value == 42); + v.emplace({1}); + assert(std::get(v).size == 1); +} + +int main() +{ + test_basic(); + test_emplace_sfinae(); +} Index: test/std/utilities/variant/variant.variant/variant.status/index.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.status/index.pass.cpp @@ -0,0 +1,56 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// constexpr size_t index() const noexcept; + +#include +#include +#include +#include + +#include "test_macros.h" +#include "archetypes.hpp" +#include "variant_test_helpers.hpp" + +int main() +{ + { + using V = std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + } + { + using V = std::variant; + constexpr V v(std::in_place_index<1>); + static_assert(v.index() == 1, ""); + } + { + using V = std::variant; + V v("abc"); + assert(v.index() == 1); + v = 42; + assert(v.index() == 0); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v; + assert(v.index() == 0); + makeEmpty(v); + assert(v.index() == std::variant_npos); + } +#endif +} Index: test/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp @@ -0,0 +1,49 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// constexpr bool valueless_by_exception() const noexcept; + +#include +#include +#include +#include + +#include "test_macros.h" +#include "archetypes.hpp" +#include "variant_test_helpers.hpp" + +int main() +{ + { + using V = std::variant; + constexpr V v; + static_assert(!v.valueless_by_exception(), ""); + } + { + using V = std::variant; + const V v("abc"); + assert(!v.valueless_by_exception()); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = std::variant; + V v; + assert(!v.valueless_by_exception()); + makeEmpty(v); + assert(v.valueless_by_exception()); + } +#endif +} Index: test/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp @@ -0,0 +1,556 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +// void swap(variant& rhs) noexcept(see below) + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" +#include "test_convertible.hpp" + +struct NotSwappable { +}; +void swap(NotSwappable&, NotSwappable&) = delete; + +struct NotCopyable { + NotCopyable() = default; + NotCopyable(NotCopyable const&) = delete; + NotCopyable& operator=(NotCopyable const&) = delete; +}; + +struct NotCopyableWithSwap { + NotCopyableWithSwap() = default; + NotCopyableWithSwap(NotCopyableWithSwap const&) = delete; + NotCopyableWithSwap& operator=(NotCopyableWithSwap const&) = delete; +}; +void swap(NotCopyableWithSwap&, NotCopyableWithSwap) {} + +struct NotMoveAssignable { + NotMoveAssignable() = default; + NotMoveAssignable(NotMoveAssignable&&) = default; + NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; +}; + +struct NotMoveAssignableWithSwap { + NotMoveAssignableWithSwap() = default; + NotMoveAssignableWithSwap(NotMoveAssignableWithSwap&&) = default; + NotMoveAssignableWithSwap& operator=(NotMoveAssignableWithSwap&&) = delete; +}; +void swap(NotMoveAssignableWithSwap&, NotMoveAssignableWithSwap&) noexcept {} + +template +void do_throw() {} + +template <> +void do_throw() { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw 42; +#else + std::abort(); +#endif +} + +template +struct NothrowTypeImp { + static int move_called; + static int move_assign_called; + static int swap_called; + static void reset() { move_called = move_assign_called = swap_called = 0; } + NothrowTypeImp() = default; + explicit NothrowTypeImp(int v) : value(v) {} + NothrowTypeImp(NothrowTypeImp const& o) noexcept(NT_Copy) + : value(o.value) + { assert(false); } // never called by test + NothrowTypeImp(NothrowTypeImp&& o) noexcept(NT_Move) + : value(o.value) + { ++move_called; do_throw(); o.value = -1; } + NothrowTypeImp& operator=(NothrowTypeImp const&) noexcept(NT_CopyAssign) + { assert(false); return *this;} // never called by the tests + NothrowTypeImp& operator=(NothrowTypeImp&& o) noexcept(NT_MoveAssign) { + ++move_assign_called; + do_throw(); + value = o.value; o.value = -1; + return *this; + } + int value; +}; +template +int NothrowTypeImp::move_called = 0; +template +int NothrowTypeImp::move_assign_called = 0; +template +int NothrowTypeImp::swap_called = 0; + +template +void swap(NothrowTypeImp& lhs, + NothrowTypeImp& rhs) + noexcept(NT_Swap) { + lhs.swap_called++; + do_throw(); + int tmp = lhs.value; + lhs.value = rhs.value; + rhs.value = tmp; +} + +// throwing copy, nothrow move ctor/assign, no swap provided +using NothrowMoveable = NothrowTypeImp; +// throwing copy and move assign, nothrow move ctor, no swap provided +using NothrowMoveCtor = NothrowTypeImp; +// nothrow move ctor, throwing move assignment, swap provided +using NothrowMoveCtorWithThrowingSwap = NothrowTypeImp; +// throwing move ctor, nothrow move assignment, no swap provided +using ThrowingMoveCtor = NothrowTypeImp; +// throwing special members, nothrowing swap +using ThrowingTypeWithNothrowSwap = NothrowTypeImp; +using NothrowTypeWithThrowingSwap = NothrowTypeImp; +// throwing move assign with nothrow move and nothrow swap +using ThrowingMoveAssignNothrowMoveCtorWithSwap = NothrowTypeImp; +// throwing move assign with nothrow move but no swap. +using ThrowingMoveAssignNothrowMoveCtor = NothrowTypeImp; + +struct NonThrowingNonNoexceptType { + static int move_called; + static void reset() { move_called = 0; } + NonThrowingNonNoexceptType() = default; + NonThrowingNonNoexceptType(int v) : value(v) {} + NonThrowingNonNoexceptType(NonThrowingNonNoexceptType&& o) noexcept(false) + : value(o.value) { + ++move_called; + o.value = -1; + } + NonThrowingNonNoexceptType& operator=(NonThrowingNonNoexceptType&&) noexcept(false) { + assert(false); // never called by the tests. + return *this; + } + int value; +}; +int NonThrowingNonNoexceptType::move_called = 0; + +struct ThrowsOnSecondMove { + int value; + int move_count; + ThrowsOnSecondMove(int v) : value(v), move_count(0) {} + ThrowsOnSecondMove(ThrowsOnSecondMove&& o) noexcept(false) + : value(o.value), move_count(o.move_count + 1) { + if (move_count == 2) + do_throw(); + o.value = -1; + } + ThrowsOnSecondMove& operator=(ThrowsOnSecondMove&&) { + assert(false); // not called by test + return *this; + } +}; + + +void test_swap_valueless_by_exception() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = std::variant; + { // both empty + V v1; makeEmpty(v1); + V v2; makeEmpty(v2); + assert(MakeEmptyT::alive == 0); + { // member swap + v1.swap(v2); + assert(v1.valueless_by_exception()); + assert(v2.valueless_by_exception()); + assert(MakeEmptyT::alive == 0); + } + { // non-member swap + swap(v1, v2); + assert(v1.valueless_by_exception()); + assert(v2.valueless_by_exception()); + assert(MakeEmptyT::alive == 0); + } + } + { // only one empty + V v1(42); + V v2; makeEmpty(v2); + { // member swap + v1.swap(v2); + assert(v1.valueless_by_exception()); + assert(std::get<0>(v2) == 42); + // swap again + v2.swap(v1); + assert(v2.valueless_by_exception()); + assert(std::get<0>(v1) == 42); + } + { // non-member swap + swap(v1, v2); + assert(v1.valueless_by_exception()); + assert(std::get<0>(v2) == 42); + // swap again + swap(v1, v2); + assert(v2.valueless_by_exception()); + assert(std::get<0>(v1) == 42); + } + } +#endif +} + +void test_swap_same_alternative() +{ + { + using T = ThrowingTypeWithNothrowSwap; + using V = std::variant; + T::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<0>, 100); + v1.swap(v2); + assert(T::swap_called == 1); + assert(std::get<0>(v1).value == 100); + assert(std::get<0>(v2).value == 42); + swap(v1, v2); + assert(T::swap_called == 2); + assert(std::get<0>(v1).value == 42); + assert(std::get<0>(v2).value == 100); + } + { + using T = NothrowMoveable; + using V = std::variant; + T::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<0>, 100); + v1.swap(v2); + assert(T::swap_called == 0); + assert(T::move_called == 1); + assert(T::move_assign_called == 2); + assert(std::get<0>(v1).value == 100); + assert(std::get<0>(v2).value == 42); + T::reset(); + swap(v1, v2); + assert(T::swap_called == 0); + assert(T::move_called == 1); + assert(T::move_assign_called == 2); + assert(std::get<0>(v1).value == 42); + assert(std::get<0>(v2).value == 100); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using T = NothrowTypeWithThrowingSwap; + using V = std::variant; + T::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<0>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T::swap_called == 1); + assert(T::move_called == 0); + assert(T::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<0>(v2).value == 100); + } + { + using T = ThrowingMoveCtor; + using V = std::variant; + T::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<0>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T::move_called == 1); // call threw + assert(T::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); // throw happend before v1 was moved from + assert(std::get<0>(v2).value == 100); + } + { + using T = ThrowingMoveAssignNothrowMoveCtor; + using V = std::variant; + T::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<0>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T::move_called == 1); + assert(T::move_assign_called == 1); // call threw and didn't complete + assert(std::get<0>(v1).value == -1); // v1 was moved from + assert(std::get<0>(v2).value == 100); + } +#endif +} + + +void test_swap_different_alternatives() +{ + { + using T = NothrowMoveCtorWithThrowingSwap; + using V = std::variant; + T::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<1>, 100); + v1.swap(v2); + assert(T::swap_called == 0); + // The libc++ implementation double copies the argument, and not + // the variant swap is called on. + assert(T::move_called == 1); + assert(T::move_assign_called == 0); + assert(std::get<1>(v1) == 100); + assert(std::get<0>(v2).value == 42); + T::reset(); + swap(v1, v2); + assert(T::swap_called == 0); + assert(T::move_called == 2); + assert(T::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<1>(v2) == 100); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using T1 = ThrowingTypeWithNothrowSwap; + using T2 = NonThrowingNonNoexceptType; + using V = std::variant; + T1::reset(); + T2::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T1::swap_called == 0); + assert(T1::move_called == 1); // throws + assert(T1::move_assign_called == 0); + assert(T2::move_called == 1); + assert(std::get<0>(v1).value == 42); + assert(v2.valueless_by_exception()); + } + { + using T1 = NonThrowingNonNoexceptType; + using T2 = ThrowingTypeWithNothrowSwap; + using V = std::variant; + T1::reset(); + T2::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T2::move_called == 1); + assert(T2::swap_called == 0); + assert(T2::move_called == 1); // throws + assert(T2::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<1>(v2).value == 100); + } + { + using T1 = ThrowsOnSecondMove; + using T2 = NonThrowingNonNoexceptType; + using V = std::variant; + T2::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<1>, 100); + v1.swap(v2); + assert(T2::move_called == 2); + assert(std::get<1>(v1).value == 100); + assert(std::get<0>(v2).value == 42); + assert(std::get<0>(v2).move_count == 1); + } + { + using T1 = NonThrowingNonNoexceptType; + using T2 = ThrowsOnSecondMove; + using V = std::variant; + T1::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) {} + assert(T1::move_called == 1); + assert(v1.valueless_by_exception()); + assert(std::get<0>(v2).value == 42); + } + { + // testing libc++ extension. If either variant stores a nothrow move + // constructible type v1.swap(v2) provides the strong exception safety + // guarentee. + using T1 = ThrowingTypeWithNothrowSwap; + using T2 = NothrowMoveable; + using V = std::variant; + T1::reset(); + T2::reset(); + V v1(std::in_place_index<0>, 42); + V v2(std::in_place_index<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + assert(T1::swap_called == 0); + assert(T1::move_called == 1); + assert(T1::move_assign_called == 0); + assert(T2::swap_called == 0); + assert(T2::move_called == 2); + assert(T2::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<1>(v2).value == 100); + // swap again, but call v2's swap. + T1::reset(); + T2::reset(); + try { + v2.swap(v1); + assert(false); + } catch (int) { + } + assert(T1::swap_called == 0); + assert(T1::move_called == 1); + assert(T1::move_assign_called == 0); + assert(T2::swap_called == 0); + assert(T2::move_called == 2); + assert(T2::move_assign_called == 0); + assert(std::get<0>(v1).value == 42); + assert(std::get<1>(v2).value == 100); + } +#endif +} + +template +constexpr auto has_swap_member_imp(int) -> decltype(std::declval().swap(std::declval()), true) +{ return true; } + +template +constexpr auto has_swap_member_imp(long) -> bool { return false; } + +template +constexpr bool has_swap_member() { return has_swap_member_imp(0); } + +void test_swap_sfinae() +{ + { + // This variant type does not provide either a member or non-member swap + // but is still swappable via the generic swap algorithm, since the + // variant is move constructible and move assignable. + using V = std::variant; + static_assert(!has_swap_member()); + static_assert(std::is_swappable_v, ""); + } + { + using V = std::variant; + static_assert(!has_swap_member() && !std::is_swappable_v, ""); + } + { + using V = std::variant; + static_assert(!has_swap_member() && !std::is_swappable_v, ""); + } + { + using V = std::variant; + static_assert(!has_swap_member() && !std::is_swappable_v, ""); + } +} + +void test_swap_noexcept() +{ + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(!std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(!std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(!std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = std::variant; + static_assert(std::is_swappable_v && has_swap_member(), ""); + static_assert(std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + // This variant type does not provide either a member or non-member swap + // but is still swappable via the generic swap algorithm, since the + // variant is move constructible and move assignable. + using V = std::variant; + static_assert(!has_swap_member()); + static_assert(std::is_swappable_v, ""); + static_assert(std::is_nothrow_swappable_v, ""); + V v1, v2; + swap(v1, v2); + } +} + +int main() +{ + test_swap_valueless_by_exception(); + test_swap_same_alternative(); + test_swap_different_alternatives(); + test_swap_sfinae(); + test_swap_noexcept(); +} Index: test/std/utilities/variant/variant.variant/variant_array.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant_array.fail.cpp @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" +#include "test_convertible.hpp" + +int main() +{ + // expected-error@variant:* 3 {{static_assert failed}} + std::variant v; // expected-note {{requested here}} + std::variant v2; // expected-note {{requested here}} + std::variant v3; // expected-note {{requested here}} +} Index: test/std/utilities/variant/variant.variant/variant_empty.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant_empty.fail.cpp @@ -0,0 +1,26 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +int main() +{ + // expected-error@variant:* 1 {{static_assert failed}} + std::variant<> v; // expected-note {{requested here}} +} Index: test/std/utilities/variant/variant.variant/variant_reference.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant_reference.fail.cpp @@ -0,0 +1,28 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" + +int main() +{ + // expected-error@variant:* 3 {{static_assert failed}} + std::variant v; // expected-note {{requested here}} + std::variant v2; // expected-note {{requested here}} + std::variant v3; // expected-note {{requested here}} +} Index: test/std/utilities/variant/variant.variant/variant_void.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.variant/variant_void.fail.cpp @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template class variant; + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.hpp" +#include "test_convertible.hpp" + +int main() +{ + // expected-error@variant:* 3 {{static_assert failed}} + std::variant v; // expected-note {{requested here}} + std::variant v2; // expected-note {{requested here}} + std::variant v3; // expected-note {{requested here}} +} Index: test/std/utilities/variant/variant.visit/visit.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -0,0 +1,293 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "type_id.h" +#include "variant_test_helpers.hpp" + + +enum CallType : unsigned { + CT_None, + CT_NonConst = 1, + CT_Const = 2, + CT_LValue = 4, + CT_RValue = 8 +}; + +inline constexpr CallType operator|(CallType LHS, CallType RHS) { + return static_cast(static_cast(LHS) | static_cast(RHS)); +} + +struct ForwardingCallObject { + + template + bool operator()(Args&&... args) & { + set_call(CT_NonConst | CT_LValue); + return true; + } + + template + bool operator()(Args&&... args) const & { + set_call(CT_Const | CT_LValue); + return true; + } + + // Don't allow the call operator to be invoked as an rvalue. + template + bool operator()(Args&&... args) && { + set_call(CT_NonConst | CT_RValue); + return true; + } + + template + bool operator()(Args&&... args) const && { + set_call(CT_Const | CT_RValue); + return true; + } + + template + static void set_call(CallType type) { + assert(last_call_type == CT_None); + assert(last_call_args == nullptr); + last_call_type = type; + last_call_args = std::addressof(makeArgumentID()); + } + + template + static bool check_call(CallType type) { + bool result = + last_call_type == type + && last_call_args + && *last_call_args == makeArgumentID(); + last_call_type = CT_None; + last_call_args = nullptr; + return result; + } + + static CallType last_call_type; + static TypeID const* last_call_args; +}; + +CallType ForwardingCallObject::last_call_type = CT_None; +TypeID const* ForwardingCallObject::last_call_args = nullptr; + + +void test_call_operator_forwarding() +{ + using Fn = ForwardingCallObject; + Fn obj{}; + Fn const& cobj = obj; + { // test call operator forwarding - single variant, single arg + using V = std::variant; + V v(42); + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + { // test call operator forwarding - single variant, multi arg + using V = std::variant; + V v(42l); + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + { // test call operator forwarding - multi variant, multi arg + using V = std::variant; + using V2 = std::variant; + V v(42l); + V2 v2("hello"); + std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); + } +} + +void test_argument_forwarding() +{ + using Fn = ForwardingCallObject; + Fn obj{}; + const auto Val = CT_LValue | CT_NonConst; + { // single argument - value type + using V = std::variant; + V v(42); + V const& cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { // single argument - lvalue reference + using V = std::variant; + int x = 42; + V v(x); + V const& cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } + { // single argument - rvalue reference + using V = std::variant; + int x = 42; + V v(std::move(x)); + V const& cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } + { // multi argument - multi variant + using S = std::string const&; + using V = std::variant; + std::string const str = "hello"; + long l = 43; + V v1(42); V const& cv1 = v1; + V v2(str); V const& cv2 = v2; + V v3(std::move(l)); V const& cv3 = v3; + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(Val))); + std::visit(obj, cv1, cv2, std::move(v3)); + assert((Fn::check_call(Val))); + } +#endif +} + +struct ReturnFirst { + template + constexpr int operator()(int f, Args&&...) const { + return f; + } +}; + +struct ReturnArity { + template + constexpr int operator()(Args&&...) const { + return sizeof...(Args); + } +}; + +void test_constexpr() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + { + using V = std::variant; + constexpr V v(42); + static_assert(std::visit(obj, v) == 42, ""); + } + { + using V = std::variant; + constexpr V v(42l); + static_assert(std::visit(obj, v) == 42, ""); + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); + } +} + +void test_exceptions() { +#ifndef TEST_HAS_NO_EXCEPTIONS + ReturnArity obj{}; + auto test = [&](auto&&... args) { + try { + std::visit(obj, args...); + } catch (std::bad_variant_access const&) { + return true; + } catch (...) {} + return false; + }; + { + using V = std::variant; + V v; makeEmpty(v); + assert(test(v)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; makeEmpty(v); + V2 v2("hello"); + assert(test(v, v2)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; makeEmpty(v); + V2 v2("hello"); + assert(test(v2, v)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; makeEmpty(v); + V2 v2; makeEmpty(v2); + assert(test(v, v2)); + } +#endif +} + +int main() { + test_call_operator_forwarding(); + test_argument_forwarding(); + test_constexpr(); + test_exceptions(); +} Index: test/support/variant_test_helpers.hpp =================================================================== --- /dev/null +++ test/support/variant_test_helpers.hpp @@ -0,0 +1,80 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef SUPPORT_VARIANT_TEST_HELPERS_HPP +#define SUPPORT_VARIANT_TEST_HELPERS_HPP + +#include +#include + +#include "test_macros.h" + +#if TEST_STD_VER <= 14 +#error This file requires C++17 +#endif + +// FIXME: Currently the variant tests are disabled using this macro. +#define TEST_VARIANT_HAS_NO_REFERENCES + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct CopyThrows { + CopyThrows() = default; + CopyThrows(CopyThrows const&) { throw 42; } + CopyThrows& operator=(CopyThrows const&) { throw 42; } +}; + +struct MoveThrows { + static int alive; + MoveThrows() { ++alive; } + MoveThrows(MoveThrows const&) {++alive;} + MoveThrows(MoveThrows&&) { throw 42; } + MoveThrows& operator=(MoveThrows const&) { return *this; } + MoveThrows& operator=(MoveThrows&&) { throw 42; } + ~MoveThrows() { --alive; } +}; + +int MoveThrows::alive = 0; + +struct MakeEmptyT { + static int alive; + MakeEmptyT() { ++alive; } + MakeEmptyT(MakeEmptyT const&) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + MakeEmptyT(MakeEmptyT &&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT const&) { + throw 42; + } + MakeEmptyT& operator=(MakeEmptyT&&) { + throw 42; + } + ~MakeEmptyT() { --alive; } +}; +static_assert(std::is_swappable_v, ""); // required for test + +int MakeEmptyT::alive = 0; + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place_type); + try { + v = v2; + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + + +#endif // SUPPORT_VARIANT_TEST_HELPERS_HPP