diff --git a/.clang-format b/.clang-format index 0da8d3427a..a647d69744 100644 --- a/.clang-format +++ b/.clang-format @@ -31,6 +31,7 @@ AttributeMacros: [ '_ALIGNAS', '_LIBCUDACXX_ALIGNOF', '_LIBCUDACXX_ALWAYS_INLINE', + '_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS', '_LIBCUDACXX_CONSTEXPR_AFTER_CXX11', '_LIBCUDACXX_CONSTEXPR_AFTER_CXX14', '_LIBCUDACXX_CONSTEXPR_AFTER_CXX20', diff --git a/libcudacxx/include/cuda/std/detail/libcxx/include/CMakeLists.txt b/libcudacxx/include/cuda/std/detail/libcxx/include/CMakeLists.txt index 704c28c7c0..69ba29d886 100644 --- a/libcudacxx/include/cuda/std/detail/libcxx/include/CMakeLists.txt +++ b/libcudacxx/include/cuda/std/detail/libcxx/include/CMakeLists.txt @@ -327,6 +327,7 @@ set(files __utility/swap.h __utility/to_underlying.h __utility/unreachable.h + __variant/monostate.h __verbose_abort algorithm any diff --git a/libcudacxx/include/cuda/std/detail/libcxx/include/__variant/monostate.h b/libcudacxx/include/cuda/std/detail/libcxx/include/__variant/monostate.h new file mode 100644 index 0000000000..a532f2f894 --- /dev/null +++ b/libcudacxx/include/cuda/std/detail/libcxx/include/__variant/monostate.h @@ -0,0 +1,80 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCUDACXX___VARIANT_MONOSTATE_H +#define _LIBCUDACXX___VARIANT_MONOSTATE_H + +#ifndef __cuda_std__ +#include <__config> +#endif // __cuda_std__ + +#ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR +#include "../__compare/ordering.h" +#endif // _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR +#include "../__functional/hash.h" + +#include "../cstddef" + +#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) +# pragma GCC system_header +#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) +# pragma clang system_header +#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) +# pragma system_header +#endif // no system header + +_LIBCUDACXX_BEGIN_NAMESPACE_STD + +#if _LIBCUDACXX_STD_VER >= 11 + +struct _LIBCUDACXX_TEMPLATE_VIS monostate {}; + +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator==(monostate, monostate) noexcept { return true; } + +#if _LIBCUDACXX_STD_VER < 20 + +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator!=(monostate, monostate) noexcept { return false; } + +#endif // _LIBCUDACXX_STD_VER < 20 + +#if _LIBCUDACXX_STD_VER >= 20 && !defined(_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR) + +_LIBCUDACXX_INLINE_VISIBILITY constexpr strong_ordering operator<=>(monostate, monostate) noexcept { + return strong_ordering::equal; +} + +#else // _LIBCUDACXX_STD_VER >= 20 + +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator<(monostate, monostate) noexcept { return false; } + +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator>(monostate, monostate) noexcept { return false; } + +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator<=(monostate, monostate) noexcept { return true; } + +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator>=(monostate, monostate) noexcept { return true; } + +# endif // _LIBCUDACXX_STD_VER >= 20 + +#ifndef __cuda_std__ +template <> +struct _LIBCUDACXX_TEMPLATE_VIS hash { + using argument_type = monostate; + using result_type = size_t; + + inline _LIBCUDACXX_INLINE_VISIBILITY result_type operator()(const argument_type&) const noexcept { + return 66740831; // return a fundamentally attractive random value. + } +}; +#endif // __cuda_std__ + +#endif // _LIBCUDACXX_STD_VER >= 11 + +_LIBCUDACXX_END_NAMESPACE_STD + +#endif // _LIBCUDACXX___VARIANT_MONOSTATE_H diff --git a/libcudacxx/include/cuda/std/detail/libcxx/include/variant b/libcudacxx/include/cuda/std/detail/libcxx/include/variant index aec00c9fcb..a3238831a7 100644 --- a/libcudacxx/include/cuda/std/detail/libcxx/include/variant +++ b/libcudacxx/include/cuda/std/detail/libcxx/include/variant @@ -1,5 +1,5 @@ // -*- C++ -*- -//===------------------------------ variant -------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -22,8 +22,8 @@ namespace std { // 20.7.2.1, constructors constexpr variant() noexcept(see below); - variant(const variant&); // constexpr in C++20 - variant(variant&&) noexcept(see below); // constexpr in C++20 + constexpr variant(const variant&); + constexpr variant(variant&&) noexcept(see below); template constexpr variant(T&&) noexcept(see below); @@ -45,8 +45,8 @@ namespace std { ~variant(); // 20.7.2.3, assignment - variant& operator=(const variant&); // constexpr in C++20 - variant& operator=(variant&&) noexcept(see below); // constexpr in C++20 + constexpr variant& operator=(const variant&); + constexpr variant& operator=(variant&&) noexcept(see below); template variant& operator=(T&&) noexcept(see below); @@ -165,20 +165,29 @@ namespace std { template constexpr bool operator>=(const variant&, const variant&); + template requires (three_way_comparable && ...) + constexpr common_comparison_category_t...> + operator<=>(const variant&, const variant&); // since +C++20 + // 20.7.6, visitation template constexpr see below visit(Visitor&&, Variants&&...); + template + constexpr R visit(Visitor&&, Variants&&...); // since C++20 + // 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; + constexpr bool operator!=(monostate, monostate) noexcept; // until C++20 + constexpr bool operator<(monostate, monostate) noexcept; // until C++20 + constexpr bool operator>(monostate, monostate) noexcept; // until C++20 + constexpr bool operator<=(monostate, monostate) noexcept; // until C++20 + constexpr bool operator>=(monostate, monostate) noexcept; // until C++20 + constexpr strong_ordering operator<=>(monostate, monostate) noexcept; // since C++20 // 20.7.9, specialized algorithms template @@ -196,17 +205,60 @@ namespace std { */ -#include <__config> -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#ifndef __cuda_std__ +# include <__config> +#endif // __cuda_std__ + +#include "__assert" // all public C++ headers provide the assertion handler +#include "__availability" +#ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR +# include "__compare/common_comparison_category.h" +# include "__compare/compare_three_way_result.h" +# include "__compare/three_way_comparable.h" +#endif // _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR +#include "__functional/hash.h" +#include "__functional/invoke.h" +#include "__functional/operations.h" +#include "__functional/unary_function.h" +#include "__memory/construct_at.h" +#include "__memory/addressof.h" +#include "__tuple_dir/tuple_indices.h" +#include "__type_traits/add_const.h" +#include "__type_traits/add_cv.h" +#include "__type_traits/add_pointer.h" +#include "__type_traits/add_volatile.h" +#include "__type_traits/dependent_type.h" +#include "__type_traits/integral_constant.h" +#include "__type_traits/is_array.h" +#include "__type_traits/is_destructible.h" +#include "__type_traits/is_nothrow_move_constructible.h" +#include "__type_traits/is_trivially_copy_assignable.h" +#include "__type_traits/is_trivially_copy_constructible.h" +#include "__type_traits/is_trivially_destructible.h" +#include "__type_traits/is_trivially_move_assignable.h" +#include "__type_traits/is_trivially_move_constructible.h" +#include "__type_traits/is_void.h" +#include "__type_traits/remove_const.h" +#include "__type_traits/remove_cvref.h" +#include "__type_traits/type_identity.h" +#include "__type_traits/void_t.h" +#include "__utility/declval.h" +#include "__utility/forward.h" +#include "__utility/in_place.h" +#include "__utility/integer_sequence.h" +#include "__utility/move.h" +#include "__utility/swap.h" +#include "__variant/monostate.h" +#include "cstddef" +#include "cstdlib" +#include "initializer_list" +#include "tuple" +#include "version" + +// [variant.syn] +#ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR +# include "compare" +#endif #if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) # pragma GCC system_header @@ -216,31 +268,34 @@ namespace std { # pragma system_header #endif // no system header -_LIBCUDACXX_PUSH_MACROS -#include <__undef_macros> +#ifndef __cuda_std__ +# include -namespace std { // explicitly not using versioning namespace +_LIBCUDACXX_BEGIN_NAMESPACE_STD_NOVERSION -class _LIBCUDACXX_EXCEPTION_ABI _LIBCUDACXX_AVAILABILITY_BAD_VARIANT_ACCESS bad_variant_access : public exception { +class _LIBCUDACXX_EXCEPTION_ABI _LIBCUDACXX_AVAILABILITY_BAD_VARIANT_ACCESS bad_variant_access : public exception +{ public: - virtual const char* what() const noexcept; + const char* what() const noexcept override; }; -} // namespace std +_LIBCUDACXX_END_NAMESPACE_STD_NOVERSION -_LIBCUDACXX_BEGIN_NAMESPACE_STD +#endif // __cuda_std__ -#if _LIBCUDACXX_STD_VER > 14 +#if _LIBCUDACXX_STD_VER >= 14 -_LIBCUDACXX_NORETURN -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -void __throw_bad_variant_access() { -#ifndef _LIBCUDACXX_NO_EXCEPTIONS - throw bad_variant_access(); -#else - _CUDA_VSTD::abort(); -#endif +_LIBCUDACXX_BEGIN_NAMESPACE_STD + +_LIBCUDACXX_NORETURN inline _LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS void +__throw_bad_variant_access() +{ +# ifndef _LIBCUDACXX_NO_EXCEPTIONS + throw bad_variant_access(); +# else + NV_IF_ELSE_TARGET(NV_IS_DEVICE, (__trap();), (_CUDA_VSTD::abort();)) + _LIBCUDACXX_UNREACHABLE(); +# endif } template @@ -253,18 +308,20 @@ template _LIBCUDACXX_INLINE_VAR constexpr size_t variant_size_v = variant_size<_Tp>::value; template -struct _LIBCUDACXX_TEMPLATE_VIS variant_size : variant_size<_Tp> {}; +struct _LIBCUDACXX_TEMPLATE_VIS variant_size : variant_size<_Tp> +{}; template -struct _LIBCUDACXX_TEMPLATE_VIS variant_size : variant_size<_Tp> {}; +struct _LIBCUDACXX_TEMPLATE_VIS variant_size : variant_size<_Tp> +{}; template -struct _LIBCUDACXX_TEMPLATE_VIS variant_size - : variant_size<_Tp> {}; +struct _LIBCUDACXX_TEMPLATE_VIS variant_size : variant_size<_Tp> +{}; template -struct _LIBCUDACXX_TEMPLATE_VIS variant_size> - : integral_constant {}; +struct _LIBCUDACXX_TEMPLATE_VIS variant_size> : integral_constant +{}; template struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative; @@ -273,57 +330,95 @@ template using variant_alternative_t = typename variant_alternative<_Ip, _Tp>::type; template -struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative<_Ip, const _Tp> - : add_const> {}; +struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative<_Ip, const _Tp> : add_const> +{}; template -struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative<_Ip, volatile _Tp> - : add_volatile> {}; +struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative<_Ip, volatile _Tp> : add_volatile> +{}; template -struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative<_Ip, const volatile _Tp> - : add_cv> {}; +struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative<_Ip, const volatile _Tp> : add_cv> +{}; template -struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative<_Ip, variant<_Types...>> { - static_assert(_Ip < sizeof...(_Types), "Index out of bounds in std::variant_alternative<>"); +struct _LIBCUDACXX_TEMPLATE_VIS variant_alternative<_Ip, variant<_Types...>> +{ + static_assert(_Ip < sizeof...(_Types), "Index out of bounds in _CUDA_VSTD::variant_alternative<>"); using type = __type_pack_element<_Ip, _Types...>; }; _LIBCUDACXX_INLINE_VAR constexpr size_t variant_npos = static_cast(-1); -constexpr int __choose_index_type(unsigned int __num_elem) { - if (__num_elem < std::numeric_limits::max()) +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_CONSTEXPR_AFTER_CXX11 int __choose_index_type(unsigned int __num_elem) +{ + constexpr unsigned char __small = static_cast(-1); + constexpr unsigned short __medium = static_cast(-1); + if (__num_elem < static_cast(__small)) + { return 0; - if (__num_elem < std::numeric_limits::max()) + } + if (__num_elem < static_cast(__medium)) + { return 1; + } return 2; } template using __variant_index_t = -#ifndef _LIBCUDACXX_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION +# ifndef _LIBCUDACXX_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION unsigned int; -#else - std::tuple_element_t< - __choose_index_type(_NumAlts), - std::tuple - >; -#endif +# else + __conditional_t<__choose_index_type(_NumAlts) == 0, + unsigned char, + __conditional_t<__choose_index_type(_NumAlts) == 1, unsigned short, unsigned int>>; +# endif template constexpr _IndexType __variant_npos = static_cast<_IndexType>(-1); -namespace __find_detail { +template +class _LIBCUDACXX_TEMPLATE_VIS variant; + +template +_LIBCUDACXX_INLINE_VISIBILITY constexpr variant<_Types...>& __as_variant(variant<_Types...>& __vs) noexcept +{ + return __vs; +} + +template +_LIBCUDACXX_INLINE_VISIBILITY constexpr const variant<_Types...>& __as_variant(const variant<_Types...>& __vs) noexcept +{ + return __vs; +} + +template +_LIBCUDACXX_INLINE_VISIBILITY constexpr variant<_Types...>&& __as_variant(variant<_Types...>&& __vs) noexcept +{ + return _CUDA_VSTD::move(__vs); +} + +template +_LIBCUDACXX_INLINE_VISIBILITY constexpr const variant<_Types...>&& __as_variant(const variant<_Types...>&& __vs) noexcept +{ + return _CUDA_VSTD::move(__vs); +} + +namespace __find_detail +{ template -inline _LIBCUDACXX_INLINE_VISIBILITY -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) { +_LIBCUDACXX_INLINE_VISIBILITY constexpr size_t __find_index() +{ + constexpr bool __matches[] = {_LIBCUDACXX_TRAIT(is_same, _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; @@ -333,40 +428,50 @@ constexpr size_t __find_index() { } template -struct __find_unambiguous_index_sfinae_impl - : integral_constant {}; +struct __find_unambiguous_index_sfinae_impl : integral_constant +{}; template <> -struct __find_unambiguous_index_sfinae_impl<__not_found> {}; +struct __find_unambiguous_index_sfinae_impl<__not_found> +{}; template <> -struct __find_unambiguous_index_sfinae_impl<__ambiguous> {}; +struct __find_unambiguous_index_sfinae_impl<__ambiguous> +{}; template -struct __find_unambiguous_index_sfinae - : __find_unambiguous_index_sfinae_impl<__find_index<_Tp, _Types...>()> {}; +struct __find_unambiguous_index_sfinae : __find_unambiguous_index_sfinae_impl<__find_index<_Tp, _Types...>()> +{}; } // namespace __find_detail -namespace __variant_detail { +namespace __variant_detail +{ -struct __valueless_t {}; +struct __valueless_t +{}; -enum class _Trait { _TriviallyAvailable, _Available, _Unavailable }; +enum class _Trait +{ + _TriviallyAvailable, + _Available, + _Unavailable +}; -template class _IsTriviallyAvailable, - template class _IsAvailable> +template class _IsTriviallyAvailable, template class _IsAvailable> constexpr _Trait __trait = - _IsTriviallyAvailable<_Tp>::value - ? _Trait::_TriviallyAvailable - : _IsAvailable<_Tp>::value ? _Trait::_Available : _Trait::_Unavailable; + _IsTriviallyAvailable<_Tp>::value ? _Trait::_TriviallyAvailable + : _IsAvailable<_Tp>::value + ? _Trait::_Available + : _Trait::_Unavailable; -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr _Trait __common_trait(initializer_list<_Trait> __traits) { +_LIBCUDACXX_INLINE_VISIBILITY constexpr _Trait __common_trait(initializer_list<_Trait> __traits) +{ _Trait __result = _Trait::_TriviallyAvailable; - for (_Trait __t : __traits) { - if (static_cast(__t) > static_cast(__result)) { + for (_Trait __t : __traits) + { + if (static_cast(__t) > static_cast(__result)) + { __result = __t; } } @@ -374,253 +479,266 @@ constexpr _Trait __common_trait(initializer_list<_Trait> __traits) { } template -struct __traits { +struct __traits +{ static constexpr _Trait __copy_constructible_trait = - __common_trait({__trait<_Types, - is_trivially_copy_constructible, - is_copy_constructible>...}); + __variant_detail::__common_trait({__trait<_Types, is_trivially_copy_constructible, is_copy_constructible>...}); static constexpr _Trait __move_constructible_trait = - __common_trait({__trait<_Types, - is_trivially_move_constructible, - is_move_constructible>...}); + __variant_detail::__common_trait({__trait<_Types, is_trivially_move_constructible, is_move_constructible>...}); - static constexpr _Trait __copy_assignable_trait = __common_trait( - {__copy_constructible_trait, - __trait<_Types, is_trivially_copy_assignable, is_copy_assignable>...}); + static constexpr _Trait __copy_assignable_trait = __variant_detail::__common_trait( + {__copy_constructible_trait, __trait<_Types, is_trivially_copy_assignable, is_copy_assignable>...}); - static constexpr _Trait __move_assignable_trait = __common_trait( - {__move_constructible_trait, - __trait<_Types, is_trivially_move_assignable, is_move_assignable>...}); + static constexpr _Trait __move_assignable_trait = __variant_detail::__common_trait( + {__move_constructible_trait, __trait<_Types, is_trivially_move_assignable, is_move_assignable>...}); - static constexpr _Trait __destructible_trait = __common_trait( - {__trait<_Types, is_trivially_destructible, is_destructible>...}); + static constexpr _Trait __destructible_trait = + __variant_detail::__common_trait({__trait<_Types, is_trivially_destructible, is_destructible>...}); }; -namespace __access { +namespace __access +{ -struct __union { +struct __union +{ template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<0>) { + _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<0>) + { return _CUDA_VSTD::forward<_Vp>(__v).__head; } template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<_Ip>) { + _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<_Ip>) + { return __get_alt(_CUDA_VSTD::forward<_Vp>(__v).__tail, in_place_index<_Ip - 1>); } }; -struct __base { +struct __base +{ template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto&& __get_alt(_Vp&& __v) { - return __union::__get_alt(_CUDA_VSTD::forward<_Vp>(__v).__data, - in_place_index<_Ip>); + _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto&& __get_alt(_Vp&& __v) + { + return __union::__get_alt(_CUDA_VSTD::forward<_Vp>(__v).__data, in_place_index<_Ip>); } }; -struct __variant { +struct __variant +{ template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto&& __get_alt(_Vp&& __v) { - return __base::__get_alt<_Ip>(_CUDA_VSTD::forward<_Vp>(__v).__impl); + _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto&& __get_alt(_Vp&& __v) + { + return __base::__get_alt<_Ip>(_CUDA_VSTD::forward<_Vp>(__v).__impl_); } }; } // namespace __access -namespace __visitation { - -struct __base { - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr decltype(auto) - __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { - constexpr auto __fdiagonal = - __make_fdiagonal<_Visitor&&, - decltype(_CUDA_VSTD::forward<_Vs>(__vs).__as_base())...>(); - return __fdiagonal[__index](_CUDA_VSTD::forward<_Visitor>(__visitor), - _CUDA_VSTD::forward<_Vs>(__vs).__as_base()...); - } - - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, - _Vs&&... __vs) { - constexpr auto __fmatrix = - __make_fmatrix<_Visitor&&, - decltype(_CUDA_VSTD::forward<_Vs>(__vs).__as_base())...>(); - return __at(__fmatrix, __vs.index()...)( - _CUDA_VSTD::forward<_Visitor>(__visitor), - _CUDA_VSTD::forward<_Vs>(__vs).__as_base()...); - } - -private: - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr const _Tp& __at(const _Tp& __elem) { return __elem; } - - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto&& __at(const array<_Tp, _Np>& __elems, - size_t __index, _Indices... __indices) { - return __at(__elems[__index], __indices...); - } - - template - static constexpr void __std_visit_visitor_return_type_check() { - static_assert( - __all...>::value, - "`std::visit` requires the visitor to have a single return type."); - } - - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_farray(_Fs&&... __fs) { - __std_visit_visitor_return_type_check<__remove_cvref_t<_Fs>...>(); - using __result = array...>, sizeof...(_Fs)>; - return __result{{_CUDA_VSTD::forward<_Fs>(__fs)...}}; - } - - template - struct __dispatcher { - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) { - return __invoke( - static_cast<_Fp>(__f), - __access::__base::__get_alt<_Is>(static_cast<_Vs>(__vs))...); - } - }; - - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_dispatch(index_sequence<_Is...>) { - return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>; - } - - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_fdiagonal_impl() { - return __make_dispatch<_Fp, _Vs...>( - index_sequence<((void)__type_identity<_Vs>{}, _Ip)...>{}); - } - - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_fdiagonal_impl(index_sequence<_Is...>) { - return __base::__make_farray(__make_fdiagonal_impl<_Is, _Fp, _Vs...>()...); +namespace __visitation +{ +struct __variant +{ + // We need to guard against the final invocation where we have processed all variants + template = 0> + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr size_t + __get_runtime_index(const _Variants&...) noexcept + { + return 0; } - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_fdiagonal() { - constexpr size_t _Np = __remove_cvref_t<_Vp>::__size(); - static_assert(__all<(_Np == __remove_cvref_t<_Vs>::__size())...>::value); - return __make_fdiagonal_impl<_Fp, _Vp, _Vs...>(make_index_sequence<_Np>{}); + template = 0> + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr size_t + __get_runtime_index(const _Variant& __v, const _OtherVariants&... __vs) noexcept + { + return __v.__impl_.index(); } - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_fmatrix_impl(index_sequence<_Is...> __is) { - return __make_dispatch<_Fp, _Vs...>(__is); + template = 0> + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr size_t + __get_runtime_index(const _Variant& __v, const _OtherVariants&... __vs) noexcept + { + return __get_runtime_index<_Remaining, _CurrentVariant - 1>(__vs...); } - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_fmatrix_impl(index_sequence<_Is...>, - index_sequence<_Js...>, - _Ls... __ls) { - return __base::__make_farray(__make_fmatrix_impl<_Fp, _Vs...>( - index_sequence<_Is..., _Js>{}, __ls...)...); + // Terminal function call with all indexes determined + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr decltype(auto) __visit_impl( + integer_sequence, + integer_sequence, + const size_t, + _Visitor&& __visitor, + _Vs&&... __vs) + { + return _CUDA_VSTD::__invoke( + _CUDA_VSTD::forward<_Visitor>(__visitor), + __access::__base::__get_alt<_ProcessedIndices>(_CUDA_VSTD::forward<_Vs>(__vs).__impl_)...); } - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_fmatrix() { - return __make_fmatrix_impl<_Fp, _Vs...>( - index_sequence<>{}, make_index_sequence<__remove_cvref_t<_Vs>::__size()>{}...); - } -}; + template = 0> + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr decltype(auto) __visit_impl( + integer_sequence, + integer_sequence, + const size_t __current_index, + _Visitor&& __visitor, + _Vs&&... __vs) + { + // We found the right index, move to the next variant + if (__current_index == _CurrentIndex) + { + const size_t __next_index = + __get_runtime_index(__vs...); + return __visit_impl( + integer_sequence{}, + integer_sequence{}, + __next_index, + _CUDA_VSTD::forward<_Visitor>(__visitor), + _CUDA_VSTD::forward<_Vs>(__vs)...); + } -struct __variant { - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr decltype(auto) - __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { - return __base::__visit_alt_at(__index, - _CUDA_VSTD::forward<_Visitor>(__visitor), - _CUDA_VSTD::forward<_Vs>(__vs).__impl...); + return __visit_impl( + integer_sequence{}, + integer_sequence{}, + __current_index, + _CUDA_VSTD::forward<_Visitor>(__visitor), + _CUDA_VSTD::forward<_Vs>(__vs)...); } - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, - _Vs&&... __vs) { - return __base::__visit_alt(_CUDA_VSTD::forward<_Visitor>(__visitor), - _CUDA_VSTD::forward<_Vs>(__vs).__impl...); + // This overload is needed to tell the compiler that the recursion is indeed limited + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr decltype(auto) __visit_impl( + integer_sequence, + integer_sequence, + const size_t __current_index, + _Visitor&& __visitor, + _Vs&&... __vs) + { + // We found the right index, move to the next variant + if (__current_index == 0) + { + const size_t __next_index = + __get_runtime_index(__vs...); + return __visit_impl( + integer_sequence{}, + integer_sequence{}, + __next_index, + _CUDA_VSTD::forward<_Visitor>(__visitor), + _CUDA_VSTD::forward<_Vs>(__vs)...); + } + _LIBCUDACXX_UNREACHABLE(); } template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr decltype(auto) - __visit_value_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { - return __visit_alt_at( - __index, - __make_value_visitor(_CUDA_VSTD::forward<_Visitor>(__visitor)), - _CUDA_VSTD::forward<_Vs>(__vs)...); + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr decltype(auto) + __visit_value(_Visitor&& __visitor, _Vs&&... __vs) + { + // NOTE: We use a recursive implementation strategy here. That means we can omit the manual return type checks from + // the common function pointer implementation, as the compiler will abort if the return types do not match. + const size_t __first_index = __get_runtime_index(__vs...); + return __visit_impl( + integer_sequence{}, + integer_sequence::__size() - 1)...>{}, + __first_index, + __make_value_visitor(_CUDA_VSTD::forward<_Visitor>(__visitor)), + _CUDA_VSTD::forward<_Vs>(__vs)...); } - template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr decltype(auto) __visit_value(_Visitor&& __visitor, - _Vs&&... __vs) { - return __visit_alt( - __make_value_visitor(_CUDA_VSTD::forward<_Visitor>(__visitor)), - _CUDA_VSTD::forward<_Vs>(__vs)...); + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr _Rp + __visit_value(_Visitor&& __visitor, _Vs&&... __vs) + { + const size_t __first_index = __get_runtime_index(__vs...); + return __visit_impl( + integer_sequence{}, + integer_sequence::__size() - 1)...>{}, + __first_index, + __make_value_visitor<_Rp>(_CUDA_VSTD::forward<_Visitor>(__visitor)), + _CUDA_VSTD::forward<_Vs>(__vs)...); } private: template - static constexpr void __std_visit_exhaustive_visitor_check() { - static_assert(is_invocable_v<_Visitor, _Values...>, + _LIBCUDACXX_INLINE_VISIBILITY static constexpr void __std_visit_exhaustive_visitor_check() + { + static_assert(_LIBCUDACXX_TRAIT(is_invocable, _Visitor, _Values...), "`std::visit` requires the visitor to be exhaustive."); } template - struct __value_visitor { + struct __value_visitor + { + template + _LIBCUDACXX_INLINE_VISIBILITY constexpr decltype(auto) operator()(_Alts&&... __alts) const + { + __std_visit_exhaustive_visitor_check<_Visitor, decltype((_CUDA_VSTD::forward<_Alts>(__alts).__value))...>(); + return _CUDA_VSTD::__invoke( + _CUDA_VSTD::forward<_Visitor>(__visitor), _CUDA_VSTD::forward<_Alts>(__alts).__value...); + } + _Visitor&& __visitor; + }; + + template + struct __value_visitor_return_type + { + template + _LIBCUDACXX_INLINE_VISIBILITY constexpr _Rp operator()(_Alts&&... __alts) const + { + __std_visit_exhaustive_visitor_check<_Visitor, decltype((_CUDA_VSTD::forward<_Alts>(__alts).__value))...>(); + return _CUDA_VSTD::__invoke( + _CUDA_VSTD::forward<_Visitor>(__visitor), _CUDA_VSTD::forward<_Alts>(__alts).__value...); + } + _Visitor&& __visitor; + }; + + template + struct __value_visitor_return_type + { template - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr decltype(auto) operator()(_Alts&&... __alts) const { - __std_visit_exhaustive_visitor_check< - _Visitor, - decltype((_CUDA_VSTD::forward<_Alts>(__alts).__value))...>(); - return __invoke(_CUDA_VSTD::forward<_Visitor>(__visitor), - _CUDA_VSTD::forward<_Alts>(__alts).__value...); + _LIBCUDACXX_INLINE_VISIBILITY constexpr void operator()(_Alts&&... __alts) const + { + __std_visit_exhaustive_visitor_check<_Visitor, decltype((_CUDA_VSTD::forward<_Alts>(__alts).__value))...>(); + _CUDA_VSTD::__invoke(_CUDA_VSTD::forward<_Visitor>(__visitor), _CUDA_VSTD::forward<_Alts>(__alts).__value...); } _Visitor&& __visitor; }; template - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr auto __make_value_visitor(_Visitor&& __visitor) { + _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto __make_value_visitor(_Visitor&& __visitor) + { return __value_visitor<_Visitor>{_CUDA_VSTD::forward<_Visitor>(__visitor)}; } + + template + _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto __make_value_visitor(_Visitor&& __visitor) + { + return __value_visitor_return_type<_Rp, _Visitor>{_CUDA_VSTD::forward<_Visitor>(__visitor)}; + } }; } // namespace __visitation template -struct _LIBCUDACXX_TEMPLATE_VIS __alt { +struct _LIBCUDACXX_TEMPLATE_VIS __alt +{ using __value_type = _Tp; template - inline _LIBCUDACXX_INLINE_VISIBILITY - explicit constexpr __alt(in_place_t, _Args&&... __args) - : __value(_CUDA_VSTD::forward<_Args>(__args)...) {} + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr __alt(in_place_t, _Args&&... __args) + : __value(_CUDA_VSTD::forward<_Args>(__args)...) + {} __value_type __value; }; @@ -629,155 +747,255 @@ template <_Trait _DestructibleTrait, size_t _Index, class... _Types> union _LIBCUDACXX_TEMPLATE_VIS __union; template <_Trait _DestructibleTrait, size_t _Index> -union _LIBCUDACXX_TEMPLATE_VIS __union<_DestructibleTrait, _Index> {}; - -#define _LIBCUDACXX_VARIANT_UNION(destructible_trait, destructor) \ - template \ - union _LIBCUDACXX_TEMPLATE_VIS __union { \ - public: \ - inline _LIBCUDACXX_INLINE_VISIBILITY \ - explicit constexpr __union(__valueless_t) noexcept : __dummy{} {} \ - \ - template \ - inline _LIBCUDACXX_INLINE_VISIBILITY \ - explicit constexpr __union(in_place_index_t<0>, _Args&&... __args) \ - : __head(in_place, _CUDA_VSTD::forward<_Args>(__args)...) {} \ - \ - template \ - inline _LIBCUDACXX_INLINE_VISIBILITY \ - explicit constexpr __union(in_place_index_t<_Ip>, _Args&&... __args) \ - : __tail(in_place_index<_Ip - 1>, _CUDA_VSTD::forward<_Args>(__args)...) {} \ - \ - __union(const __union&) = default; \ - __union(__union&&) = default; \ - \ - destructor \ - \ - __union& operator=(const __union&) = default; \ - __union& operator=(__union&&) = default; \ - \ - private: \ - char __dummy; \ - __alt<_Index, _Tp> __head; \ - __union __tail; \ - \ - friend struct __access::__union; \ - } - -_LIBCUDACXX_VARIANT_UNION(_Trait::_TriviallyAvailable, ~__union() = default;); -_LIBCUDACXX_VARIANT_UNION(_Trait::_Available, ~__union() {}); -_LIBCUDACXX_VARIANT_UNION(_Trait::_Unavailable, ~__union() = delete;); - -#undef _LIBCUDACXX_VARIANT_UNION +union _LIBCUDACXX_TEMPLATE_VIS __union<_DestructibleTrait, _Index> +{}; + +# define _LIBCUDACXX_VARIANT_UNION_BODY(destructible_trait) \ + \ + private: \ + char __dummy; \ + __alt<_Index, _Tp> __head; \ + __union __tail; \ + \ + friend struct __access::__union; \ + \ + public: \ + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr __union(__valueless_t) noexcept \ + : __dummy{} \ + {} \ + \ + template \ + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr __union(in_place_index_t<0>, _Args&&... __args) \ + : __head(in_place, _CUDA_VSTD::forward<_Args>(__args)...) \ + {} \ + \ + template \ + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr __union(in_place_index_t<_Ip>, _Args&&... __args) \ + : __tail(in_place_index<_Ip - 1>, _CUDA_VSTD::forward<_Args>(__args)...) \ + {} \ + \ + __union(const __union&) = default; \ + __union(__union&&) = default; \ + __union& operator=(const __union&) = default; \ + __union& operator=(__union&&) = default; + +template +union _LIBCUDACXX_TEMPLATE_VIS __union<_Trait::_TriviallyAvailable, _Index, _Tp, _Types...> +{ + _LIBCUDACXX_VARIANT_UNION_BODY(_Trait::_TriviallyAvailable) + ~__union() = default; +}; + +template +union _LIBCUDACXX_TEMPLATE_VIS __union<_Trait::_Available, _Index, _Tp, _Types...> +{ + _LIBCUDACXX_VARIANT_UNION_BODY(_Trait::_Available) + _LIBCUDACXX_INLINE_VISIBILITY ~__union() {} +}; + +template +union _LIBCUDACXX_TEMPLATE_VIS __union<_Trait::_Unavailable, _Index, _Tp, _Types...> +{ + _LIBCUDACXX_VARIANT_UNION_BODY(_Trait::_Unavailable) + _LIBCUDACXX_INLINE_VISIBILITY ~__union() = delete; +}; + +# undef _LIBCUDACXX_VARIANT_UNION_BODY template <_Trait _DestructibleTrait, class... _Types> -class _LIBCUDACXX_TEMPLATE_VIS __base { +class _LIBCUDACXX_TEMPLATE_VIS __base +{ public: using __index_t = __variant_index_t; - inline _LIBCUDACXX_INLINE_VISIBILITY - explicit constexpr __base(__valueless_t tag) noexcept - : __data(tag), __index(__variant_npos<__index_t>) {} + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr __base(__valueless_t __tag) noexcept + : __data(__tag) + , __index(__variant_npos<__index_t>) + {} template - inline _LIBCUDACXX_INLINE_VISIBILITY - explicit constexpr __base(in_place_index_t<_Ip>, _Args&&... __args) - : - __data(in_place_index<_Ip>, _CUDA_VSTD::forward<_Args>(__args)...), - __index(_Ip) {} - - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr bool valueless_by_exception() const noexcept { + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr __base(in_place_index_t<_Ip>, _Args&&... __args) + : __data(in_place_index<_Ip>, _CUDA_VSTD::forward<_Args>(__args)...) + , __index(_Ip) + {} + + _LIBCUDACXX_INLINE_VISIBILITY constexpr bool valueless_by_exception() const noexcept + { return index() == variant_npos; } - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr size_t index() const noexcept { + _LIBCUDACXX_INLINE_VISIBILITY constexpr size_t index() const noexcept + { return __index == __variant_npos<__index_t> ? variant_npos : __index; } protected: - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr auto&& __as_base() & { return *this; } + _LIBCUDACXX_INLINE_VISIBILITY constexpr auto&& __as_base() & + { + return *this; + } - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr auto&& __as_base() && { return _CUDA_VSTD::move(*this); } + _LIBCUDACXX_INLINE_VISIBILITY constexpr auto&& __as_base() && + { + return _CUDA_VSTD::move(*this); + } - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr auto&& __as_base() const & { return *this; } + _LIBCUDACXX_INLINE_VISIBILITY constexpr auto&& __as_base() const& + { + return *this; + } - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr auto&& __as_base() const && { return _CUDA_VSTD::move(*this); } + _LIBCUDACXX_INLINE_VISIBILITY constexpr auto&& __as_base() const&& + { + return _CUDA_VSTD::move(*this); + } - inline _LIBCUDACXX_INLINE_VISIBILITY - static constexpr size_t __size() { return sizeof...(_Types); } + _LIBCUDACXX_INLINE_VISIBILITY static constexpr size_t __size() + { + return sizeof...(_Types); + } __union<_DestructibleTrait, 0, _Types...> __data; __index_t __index; friend struct __access::__base; - friend struct __visitation::__base; }; template -class _LIBCUDACXX_TEMPLATE_VIS __destructor; - -#define _LIBCUDACXX_VARIANT_DESTRUCTOR(destructible_trait, destructor, destroy) \ - template \ - class _LIBCUDACXX_TEMPLATE_VIS __destructor<__traits<_Types...>, \ - destructible_trait> \ - : public __base { \ - using __base_type = __base; \ - using __index_t = typename __base_type::__index_t; \ - \ - public: \ - using __base_type::__base_type; \ - using __base_type::operator=; \ - \ - __destructor(const __destructor&) = default; \ - __destructor(__destructor&&) = default; \ - destructor \ - __destructor& operator=(const __destructor&) = default; \ - __destructor& operator=(__destructor&&) = default; \ - \ - protected: \ - inline _LIBCUDACXX_INLINE_VISIBILITY \ - destroy \ - } - -_LIBCUDACXX_VARIANT_DESTRUCTOR( - _Trait::_TriviallyAvailable, - ~__destructor() = default;, - void __destroy() noexcept { this->__index = __variant_npos<__index_t>; }); - -_LIBCUDACXX_VARIANT_DESTRUCTOR( - _Trait::_Available, - ~__destructor() { __destroy(); }, - void __destroy() noexcept { - if (!this->valueless_by_exception()) { - __visitation::__base::__visit_alt( - [](auto& __alt) noexcept { - using __alt_type = __remove_cvref_t; - __alt.~__alt_type(); - }, - *this); - } - this->__index = __variant_npos<__index_t>; - }); +class _LIBCUDACXX_TEMPLATE_VIS __dtor; + +# define _LIBCUDACXX_VARIANT_DESTRUCTOR_BODY(destructible_trait) \ + using __base_type = __base; \ + using __index_t = typename __base_type::__index_t; \ + \ + public: \ + using __base_type::__base_type; \ + using __base_type::operator=; \ + \ + __dtor(const __dtor&) = default; \ + __dtor(__dtor&&) = default; \ + __dtor& operator=(const __dtor&) = default; \ + __dtor& operator=(__dtor&&) = default; + +template +class _LIBCUDACXX_TEMPLATE_VIS __dtor<__traits<_Types...>, _Trait::_TriviallyAvailable> + : public __base<_Trait::_TriviallyAvailable, _Types...> +{ + _LIBCUDACXX_VARIANT_DESTRUCTOR_BODY(_Trait::_TriviallyAvailable) + ~__dtor() = default; + +protected: + _LIBCUDACXX_INLINE_VISIBILITY void __destroy() noexcept + { + this->__index = __variant_npos<__index_t>; + } +}; + +template +class _LIBCUDACXX_TEMPLATE_VIS __dtor<__traits<_Types...>, _Trait::_Available> + : public __base<_Trait::_Available, _Types...> +{ + struct __visitor + { + template + _LIBCUDACXX_INLINE_VISIBILITY void operator()(_Alt& __alt) const noexcept + { + using __alt_type = __remove_cvref_t; + __alt.~__alt_type(); + } + }; + + _LIBCUDACXX_VARIANT_DESTRUCTOR_BODY(_Trait::_Available) + _LIBCUDACXX_INLINE_VISIBILITY ~__dtor() noexcept + { + __destroy(); + } + +protected: + _LIBCUDACXX_INLINE_VISIBILITY void __destroy() noexcept + { + if (!this->valueless_by_exception()) + { + constexpr size_t __np = __remove_cvref_t<__dtor>::__size(); + __destroy(integral_constant{}, this->__index); + } + this->__index = __variant_npos<__index_t>; + } + +private: + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY void + __destroy(integral_constant, const size_t __index) noexcept + { + if (__index == _CurrentIndex) + { + using __alt_type = __remove_cvref_t(this->__as_base()))>; + __access::__base::__get_alt<_CurrentIndex>(this->__as_base()).~__alt_type(); + return; + } + __destroy(integral_constant{}, __index); + } + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY void + __destroy(integral_constant, const size_t __index) noexcept + { + if (__index == 0) + { + using __alt_type = __remove_cvref_t(this->__as_base()))>; + __access::__base::__get_alt<0>(this->__as_base()).~__alt_type(); + return; + } + // We already checked that every variant has a value, so we should never reach this line + _LIBCUDACXX_UNREACHABLE(); + } +}; -_LIBCUDACXX_VARIANT_DESTRUCTOR( - _Trait::_Unavailable, - ~__destructor() = delete;, - void __destroy() noexcept = delete;); +template +class _LIBCUDACXX_TEMPLATE_VIS __dtor<__traits<_Types...>, _Trait::_Unavailable> + : public __base<_Trait::_Unavailable, _Types...> +{ + _LIBCUDACXX_VARIANT_DESTRUCTOR_BODY(_Trait::_Unavailable) + _LIBCUDACXX_INLINE_VISIBILITY ~__dtor() = delete; + +protected: + _LIBCUDACXX_INLINE_VISIBILITY void __destroy() noexcept = delete; +}; -#undef _LIBCUDACXX_VARIANT_DESTRUCTOR +# undef _LIBCUDACXX_VARIANT_DESTRUCTOR_BODY template -class _LIBCUDACXX_TEMPLATE_VIS __constructor : public __destructor<_Traits> { - using __base_type = __destructor<_Traits>; +class _LIBCUDACXX_TEMPLATE_VIS __ctor : public __dtor<_Traits> +{ + using __base_type = __dtor<_Traits>; + + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr void + __generic_construct_impl(integral_constant, const size_t __index, __ctor& __lhs, _Rhs&& __rhs) + { + if (__index == _CurrentIndex) + { + __construct_at(_CUDA_VSTD::addressof(__access::__base::__get_alt<_CurrentIndex>(__lhs.__as_base())), + in_place, + __access::__base::__get_alt<_CurrentIndex>(_CUDA_VSTD::forward<_Rhs>(__rhs).__as_base()).__value); + return; + } + __generic_construct_impl( + integral_constant{}, __index, __lhs, _CUDA_VSTD::forward<_Rhs>(__rhs)); + } + + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr void + __generic_construct_impl(integral_constant, const size_t __index, __ctor& __lhs, _Rhs&& __rhs) + { + if (__index == 0) + { + __construct_at(_CUDA_VSTD::addressof(__access::__base::__get_alt<0>(__lhs.__as_base())), + in_place, + __access::__base::__get_alt<0>(_CUDA_VSTD::forward<_Rhs>(__rhs).__as_base()).__value); + return; + } + // We already checked that every variant has a value, so we should never reach this line + _LIBCUDACXX_UNREACHABLE(); + } public: using __base_type::__base_type; @@ -785,27 +1003,22 @@ public: protected: template - inline _LIBCUDACXX_INLINE_VISIBILITY - static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) { - ::new ((void*)_CUDA_VSTD::addressof(__a)) - __alt<_Ip, _Tp>(in_place, _CUDA_VSTD::forward<_Args>(__args)...); + _LIBCUDACXX_INLINE_VISIBILITY static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) + { + __construct_at(_CUDA_VSTD::addressof(__a), in_place, _CUDA_VSTD::forward<_Args>(__args)...); return __a.__value; } template - inline _LIBCUDACXX_INLINE_VISIBILITY - static void __generic_construct(__constructor& __lhs, _Rhs&& __rhs) { + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static void __generic_construct(__ctor& __lhs, _Rhs&& __rhs) + { __lhs.__destroy(); - if (!__rhs.valueless_by_exception()) { - __visitation::__base::__visit_alt_at( - __rhs.index(), - [](auto& __lhs_alt, auto&& __rhs_alt) { - __construct_alt( - __lhs_alt, - _CUDA_VSTD::forward(__rhs_alt).__value); - }, - __lhs, _CUDA_VSTD::forward<_Rhs>(__rhs)); - __lhs.__index = __rhs.index(); + if (!__rhs.valueless_by_exception()) + { + constexpr size_t __np = __remove_cvref_t<__ctor>::__size(); + __generic_construct_impl( + integral_constant{}, __rhs.index(), __lhs, _CUDA_VSTD::forward<_Rhs>(__rhs)); + __lhs.__index = static_cast(__rhs.index()); } } }; @@ -813,138 +1026,165 @@ protected: template class _LIBCUDACXX_TEMPLATE_VIS __move_constructor; -#define _LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, \ - move_constructor) \ - template \ - class _LIBCUDACXX_TEMPLATE_VIS __move_constructor<__traits<_Types...>, \ - move_constructible_trait> \ - : public __constructor<__traits<_Types...>> { \ - using __base_type = __constructor<__traits<_Types...>>; \ - \ - public: \ - using __base_type::__base_type; \ - using __base_type::operator=; \ - \ - __move_constructor(const __move_constructor&) = default; \ - move_constructor \ - ~__move_constructor() = default; \ - __move_constructor& operator=(const __move_constructor&) = default; \ - __move_constructor& operator=(__move_constructor&&) = default; \ - } +# define _LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, move_constructor) \ + template \ + class _LIBCUDACXX_TEMPLATE_VIS __move_constructor<__traits<_Types...>, move_constructible_trait> \ + : public __ctor<__traits<_Types...>> \ + { \ + using __base_type = __ctor<__traits<_Types...>>; \ + \ + public: \ + using __base_type::__base_type; \ + using __base_type::operator=; \ + \ + __move_constructor(const __move_constructor&) = default; \ + move_constructor ~__move_constructor() = default; \ + __move_constructor& operator=(const __move_constructor&) = default; \ + __move_constructor& operator=(__move_constructor&&) = default; \ + } -_LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR( - _Trait::_TriviallyAvailable, - __move_constructor(__move_constructor&& __that) = default;); +_LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR(_Trait::_TriviallyAvailable, + __move_constructor(__move_constructor&& __that) = default;); _LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR( - _Trait::_Available, - __move_constructor(__move_constructor&& __that) noexcept( - __all...>::value) - : __move_constructor(__valueless_t{}) { - this->__generic_construct(*this, _CUDA_VSTD::move(__that)); - }); + _Trait::_Available, + _LIBCUDACXX_INLINE_VISIBILITY __move_constructor(__move_constructor&& __that) noexcept( + __all<_LIBCUDACXX_TRAIT(is_nothrow_move_constructible, _Types)...>::value) + : __move_constructor(__valueless_t{}) { this->__generic_construct(*this, _CUDA_VSTD::move(__that)); }); -_LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR( - _Trait::_Unavailable, - __move_constructor(__move_constructor&&) = delete;); +_LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR(_Trait::_Unavailable, __move_constructor(__move_constructor&&) = delete;); -#undef _LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR +# undef _LIBCUDACXX_VARIANT_MOVE_CONSTRUCTOR template class _LIBCUDACXX_TEMPLATE_VIS __copy_constructor; -#define _LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, \ - copy_constructor) \ - template \ - class _LIBCUDACXX_TEMPLATE_VIS __copy_constructor<__traits<_Types...>, \ - copy_constructible_trait> \ - : public __move_constructor<__traits<_Types...>> { \ - using __base_type = __move_constructor<__traits<_Types...>>; \ - \ - public: \ - using __base_type::__base_type; \ - using __base_type::operator=; \ - \ - copy_constructor \ - __copy_constructor(__copy_constructor&&) = default; \ - ~__copy_constructor() = default; \ - __copy_constructor& operator=(const __copy_constructor&) = default; \ - __copy_constructor& operator=(__copy_constructor&&) = default; \ - } +# define _LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, copy_constructor) \ + template \ + class _LIBCUDACXX_TEMPLATE_VIS __copy_constructor<__traits<_Types...>, copy_constructible_trait> \ + : public __move_constructor<__traits<_Types...>> \ + { \ + using __base_type = __move_constructor<__traits<_Types...>>; \ + \ + public: \ + using __base_type::__base_type; \ + using __base_type::operator=; \ + \ + copy_constructor __copy_constructor(__copy_constructor&&) = default; \ + ~__copy_constructor() = default; \ + __copy_constructor& operator=(const __copy_constructor&) = default; \ + __copy_constructor& operator=(__copy_constructor&&) = default; \ + } -_LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR( - _Trait::_TriviallyAvailable, - __copy_constructor(const __copy_constructor& __that) = default;); +_LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR(_Trait::_TriviallyAvailable, + __copy_constructor(const __copy_constructor& __that) = default;); _LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR( - _Trait::_Available, - __copy_constructor(const __copy_constructor& __that) - : __copy_constructor(__valueless_t{}) { - this->__generic_construct(*this, __that); - }); + _Trait::_Available, _LIBCUDACXX_INLINE_VISIBILITY __copy_constructor(const __copy_constructor& __that) + : __copy_constructor(__valueless_t{}) { this->__generic_construct(*this, __that); }); -_LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR( - _Trait::_Unavailable, - __copy_constructor(const __copy_constructor&) = delete;); +_LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR(_Trait::_Unavailable, __copy_constructor(const __copy_constructor&) = delete;); -#undef _LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR +# undef _LIBCUDACXX_VARIANT_COPY_CONSTRUCTOR template -class _LIBCUDACXX_TEMPLATE_VIS __assignment : public __copy_constructor<_Traits> { +class _LIBCUDACXX_TEMPLATE_VIS __assignment : public __copy_constructor<_Traits> +{ using __base_type = __copy_constructor<_Traits>; + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY constexpr void + __generic_assign(integral_constant, const size_t __index, _Other&& __rhs) + { + if (__index == _CurrentIndex) + { + this->__assign_alt( + __access::__base::__get_alt<_CurrentIndex>(this->__as_base()), + __access::__base::__get_alt<_CurrentIndex>(_CUDA_VSTD::forward<_Other>(__rhs).__as_base()).__value); + return; + } + this->__generic_assign(integral_constant{}, __index, _CUDA_VSTD::forward<_Other>(__rhs)); + } + + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY constexpr void + __generic_assign(integral_constant, const size_t __index, _Other&& __rhs) + { + if (__index == 0) + { + this->__assign_alt(__access::__base::__get_alt<0>(this->__as_base()), + __access::__base::__get_alt<0>(_CUDA_VSTD::forward<_Other>(__rhs).__as_base()).__value); + return; + } + // We already checked that every variant has a value, so we should never reach this line + _LIBCUDACXX_UNREACHABLE(); + } + public: using __base_type::__base_type; using __base_type::operator=; template - inline _LIBCUDACXX_INLINE_VISIBILITY - auto& __emplace(_Args&&... __args) { + _LIBCUDACXX_INLINE_VISIBILITY auto& __emplace(_Args&&... __args) + { this->__destroy(); - auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), - _CUDA_VSTD::forward<_Args>(__args)...); + auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), _CUDA_VSTD::forward<_Args>(__args)...); this->__index = _Ip; return __res; } protected: - template - inline _LIBCUDACXX_INLINE_VISIBILITY - void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) { - if (this->index() == _Ip) { + template = 0> + _LIBCUDACXX_INLINE_VISIBILITY void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) + { + if (this->index() == _Ip) + { __a.__value = _CUDA_VSTD::forward<_Arg>(__arg); - } else { - struct { - void operator()(true_type) const { - __this->__emplace<_Ip>(_CUDA_VSTD::forward<_Arg>(__arg)); - } - void operator()(false_type) const { - __this->__emplace<_Ip>(_Tp(_CUDA_VSTD::forward<_Arg>(__arg))); - } - __assignment* __this; - _Arg&& __arg; - } __impl{this, _CUDA_VSTD::forward<_Arg>(__arg)}; - __impl(bool_constant || - !is_nothrow_move_constructible_v<_Tp>>{}); + } + else + { + this->__emplace<_Ip>(_CUDA_VSTD::forward<_Arg>(__arg)); + } + } + + template = 0> + _LIBCUDACXX_INLINE_VISIBILITY void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) + { + if (this->index() == _Ip) + { + __a.__value = _CUDA_VSTD::forward<_Arg>(__arg); + } + else + { + this->__emplace<_Ip>(_Tp(_CUDA_VSTD::forward<_Arg>(__arg))); } } template - inline _LIBCUDACXX_INLINE_VISIBILITY - void __generic_assign(_That&& __that) { - if (this->valueless_by_exception() && __that.valueless_by_exception()) { + _LIBCUDACXX_INLINE_VISIBILITY void __generic_assign(_That&& __that) + { + if (this->valueless_by_exception() && __that.valueless_by_exception()) + { // do nothing. - } else if (__that.valueless_by_exception()) { + } + else if (__that.valueless_by_exception()) + { this->__destroy(); - } else { - __visitation::__base::__visit_alt_at( - __that.index(), - [this](auto& __this_alt, auto&& __that_alt) { - this->__assign_alt( - __this_alt, - _CUDA_VSTD::forward(__that_alt).__value); - }, - *this, _CUDA_VSTD::forward<_That>(__that)); + } + else + { + constexpr size_t __np = __remove_cvref_t<__assignment>::__size(); + this->__generic_assign(integral_constant{}, __that.index(), _CUDA_VSTD::forward<_That>(__that)); } } }; @@ -952,720 +1192,998 @@ protected: template class _LIBCUDACXX_TEMPLATE_VIS __move_assignment; -#define _LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, \ - move_assignment) \ - template \ - class _LIBCUDACXX_TEMPLATE_VIS __move_assignment<__traits<_Types...>, \ - move_assignable_trait> \ - : public __assignment<__traits<_Types...>> { \ - using __base_type = __assignment<__traits<_Types...>>; \ - \ - public: \ - using __base_type::__base_type; \ - using __base_type::operator=; \ - \ - __move_assignment(const __move_assignment&) = default; \ - __move_assignment(__move_assignment&&) = default; \ - ~__move_assignment() = default; \ - __move_assignment& operator=(const __move_assignment&) = default; \ - move_assignment \ - } +# define _LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, move_assignment) \ + template \ + class _LIBCUDACXX_TEMPLATE_VIS __move_assignment<__traits<_Types...>, move_assignable_trait> \ + : public __assignment<__traits<_Types...>> \ + { \ + using __base_type = __assignment<__traits<_Types...>>; \ + \ + public: \ + using __base_type::__base_type; \ + using __base_type::operator=; \ + \ + __move_assignment(const __move_assignment&) = default; \ + __move_assignment(__move_assignment&&) = default; \ + ~__move_assignment() = default; \ + __move_assignment& operator=(const __move_assignment&) = default; \ + move_assignment \ + } -_LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT( - _Trait::_TriviallyAvailable, - __move_assignment& operator=(__move_assignment&& __that) = default;); +_LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT(_Trait::_TriviallyAvailable, + __move_assignment& operator=(__move_assignment&& __that) = default;); _LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT( - _Trait::_Available, - __move_assignment& operator=(__move_assignment&& __that) noexcept( - __all<(is_nothrow_move_constructible_v<_Types> && - is_nothrow_move_assignable_v<_Types>)...>::value) { - this->__generic_assign(_CUDA_VSTD::move(__that)); - return *this; - }); + _Trait::_Available, + _LIBCUDACXX_INLINE_VISIBILITY __move_assignment& + operator=(__move_assignment&& __that) noexcept( + __all<(_LIBCUDACXX_TRAIT(is_nothrow_move_constructible, _Types) + && _LIBCUDACXX_TRAIT(is_nothrow_move_assignable, _Types))...>::value) { + this->__generic_assign(_CUDA_VSTD::move(__that)); + return *this; + }); -_LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT( - _Trait::_Unavailable, - __move_assignment& operator=(__move_assignment&&) = delete;); +_LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT(_Trait::_Unavailable, __move_assignment& operator=(__move_assignment&&) = delete;); -#undef _LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT +# undef _LIBCUDACXX_VARIANT_MOVE_ASSIGNMENT template class _LIBCUDACXX_TEMPLATE_VIS __copy_assignment; -#define _LIBCUDACXX_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, \ - copy_assignment) \ - template \ - class _LIBCUDACXX_TEMPLATE_VIS __copy_assignment<__traits<_Types...>, \ - copy_assignable_trait> \ - : public __move_assignment<__traits<_Types...>> { \ - using __base_type = __move_assignment<__traits<_Types...>>; \ - \ - public: \ - using __base_type::__base_type; \ - using __base_type::operator=; \ - \ - __copy_assignment(const __copy_assignment&) = default; \ - __copy_assignment(__copy_assignment&&) = default; \ - ~__copy_assignment() = default; \ - copy_assignment \ - __copy_assignment& operator=(__copy_assignment&&) = default; \ - } +# define _LIBCUDACXX_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, copy_assignment) \ + template \ + class _LIBCUDACXX_TEMPLATE_VIS __copy_assignment<__traits<_Types...>, copy_assignable_trait> \ + : public __move_assignment<__traits<_Types...>> \ + { \ + using __base_type = __move_assignment<__traits<_Types...>>; \ + \ + public: \ + using __base_type::__base_type; \ + using __base_type::operator=; \ + \ + __copy_assignment(const __copy_assignment&) = default; \ + __copy_assignment(__copy_assignment&&) = default; \ + ~__copy_assignment() = default; \ + copy_assignment __copy_assignment& operator=(__copy_assignment&&) = default; \ + } -_LIBCUDACXX_VARIANT_COPY_ASSIGNMENT( - _Trait::_TriviallyAvailable, - __copy_assignment& operator=(const __copy_assignment& __that) = default;); +_LIBCUDACXX_VARIANT_COPY_ASSIGNMENT(_Trait::_TriviallyAvailable, + __copy_assignment& operator=(const __copy_assignment& __that) = default;); _LIBCUDACXX_VARIANT_COPY_ASSIGNMENT( - _Trait::_Available, - __copy_assignment& operator=(const __copy_assignment& __that) { - this->__generic_assign(__that); - return *this; - }); + _Trait::_Available, _LIBCUDACXX_INLINE_VISIBILITY __copy_assignment& operator=(const __copy_assignment& __that) { + this->__generic_assign(__that); + return *this; + }); -_LIBCUDACXX_VARIANT_COPY_ASSIGNMENT( - _Trait::_Unavailable, - __copy_assignment& operator=(const __copy_assignment&) = delete;); +_LIBCUDACXX_VARIANT_COPY_ASSIGNMENT(_Trait::_Unavailable, + __copy_assignment& operator=(const __copy_assignment&) = delete;); -#undef _LIBCUDACXX_VARIANT_COPY_ASSIGNMENT +# undef _LIBCUDACXX_VARIANT_COPY_ASSIGNMENT template -class _LIBCUDACXX_TEMPLATE_VIS __impl - : public __copy_assignment<__traits<_Types...>> { +class _LIBCUDACXX_TEMPLATE_VIS __impl : public __copy_assignment<__traits<_Types...>> +{ using __base_type = __copy_assignment<__traits<_Types...>>; + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr void + __swap_value(integral_constant, const size_t __index, __impl& __lhs, __impl& __rhs) + { + if (__index == _CurrentIndex) + { + using _CUDA_VSTD::swap; + swap(__access::__base::__get_alt<_CurrentIndex>(__lhs.__as_base()).__value, + __access::__base::__get_alt<_CurrentIndex>(__rhs.__as_base()).__value); + return; + } + __swap_value(integral_constant{}, __index, __lhs, __rhs); + } + + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr void + __swap_value(integral_constant, const size_t __index, __impl& __lhs, __impl& __rhs) + { + if (__index == 0) + { + using _CUDA_VSTD::swap; + swap(__access::__base::__get_alt<0>(__lhs.__as_base()).__value, + __access::__base::__get_alt<0>(__rhs.__as_base()).__value); + return; + } + // We already checked that every variant has a value, so we should never reach this line + _LIBCUDACXX_UNREACHABLE(); + } + public: - using __base_type::__base_type; - using __base_type::operator=; + using __base_type::__base_type; // get in_place_index_t constructor & friends + __impl(__impl const&) = default; + __impl(__impl&&) = default; + __impl& operator=(__impl const&) = default; + __impl& operator=(__impl&&) = default; template - inline _LIBCUDACXX_INLINE_VISIBILITY - void __assign(_Arg&& __arg) { - this->__assign_alt(__access::__base::__get_alt<_Ip>(*this), - _CUDA_VSTD::forward<_Arg>(__arg)); + _LIBCUDACXX_INLINE_VISIBILITY void __assign(_Arg&& __arg) + { + this->__assign_alt(__access::__base::__get_alt<_Ip>(*this), _CUDA_VSTD::forward<_Arg>(__arg)); } - inline _LIBCUDACXX_INLINE_VISIBILITY - void __swap(__impl& __that) { - if (this->valueless_by_exception() && __that.valueless_by_exception()) { + inline _LIBCUDACXX_INLINE_VISIBILITY void __swap(__impl& __that) + { + if (this->valueless_by_exception() && __that.valueless_by_exception()) + { // do nothing. - } else if (this->index() == __that.index()) { - __visitation::__base::__visit_alt_at( - this->index(), - [](auto& __this_alt, auto& __that_alt) { - using _CUDA_VSTD::swap; - swap(__this_alt.__value, __that_alt.__value); - }, - *this, - __that); - } else { + } + else if (this->index() == __that.index()) + { + constexpr size_t __np = __remove_cvref_t<__impl>::__size(); + __swap_value(integral_constant{}, this->index(), *this, __that); + } + else + { __impl* __lhs = this; __impl* __rhs = _CUDA_VSTD::addressof(__that); - if (__lhs->__move_nothrow() && !__rhs->__move_nothrow()) { + if (__lhs->__move_nothrow() && !__rhs->__move_nothrow()) + { _CUDA_VSTD::swap(__lhs, __rhs); } __impl __tmp(_CUDA_VSTD::move(*__rhs)); -#ifndef _LIBCUDACXX_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 guarantee. - try { +# ifndef _LIBCUDACXX_NO_EXCEPTIONS + if constexpr (__all<_LIBCUDACXX_TRAIT(is_nothrow_move_constructible, _Types)...>::value) + { this->__generic_construct(*__rhs, _CUDA_VSTD::move(*__lhs)); - } catch (...) { - if (__tmp.__move_nothrow()) { - this->__generic_construct(*__rhs, _CUDA_VSTD::move(__tmp)); + } + else + { + // 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 guarantee. + try + { + this->__generic_construct(*__rhs, _CUDA_VSTD::move(*__lhs)); + } + catch (...) + { + if (__tmp.__move_nothrow()) + { + this->__generic_construct(*__rhs, _CUDA_VSTD::move(__tmp)); + } + throw; } - throw; } -#else +# else + // this isn't consolidated with the `if constexpr` branch above due to + // `throw` being ill-formed with exceptions disabled even when discarded. this->__generic_construct(*__rhs, _CUDA_VSTD::move(*__lhs)); -#endif +# endif this->__generic_construct(*__lhs, _CUDA_VSTD::move(__tmp)); } } private: - inline _LIBCUDACXX_INLINE_VISIBILITY - bool __move_nothrow() const { - constexpr bool __results[] = {is_nothrow_move_constructible_v<_Types>...}; + inline _LIBCUDACXX_INLINE_VISIBILITY constexpr bool __move_nothrow() const + { + constexpr bool __results[] = {_LIBCUDACXX_TRAIT(is_nothrow_move_constructible, _Types)...}; return this->valueless_by_exception() || __results[this->index()]; } }; -struct __no_narrowing_check { +struct __no_narrowing_check +{ template using _Apply = __type_identity<_Dest>; }; -struct __narrowing_check { - template - static auto __test_impl(_Dest (&&)[1]) -> __type_identity<_Dest>; +struct __narrowing_check +{ + template + struct __narrowing_check_impl + {}; + + template + struct __narrowing_check_impl<_Dest, _Source, __void_t()})>> + { + using type = __type_identity<_Dest>; + }; + template - using _Apply _LIBCUDACXX_NODEBUG_TYPE = decltype(__test_impl<_Dest>({std::declval<_Source>()})); + using _Apply _LIBCUDACXX_NODEBUG = typename __narrowing_check_impl<_Dest, _Source>::type; }; template -using __check_for_narrowing _LIBCUDACXX_NODEBUG_TYPE = - typename _If< -#ifdef _LIBCUDACXX_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT - false && -#endif - is_arithmetic<_Dest>::value, - __narrowing_check, - __no_narrowing_check - >::template _Apply<_Dest, _Source>; +using __check_for_narrowing _LIBCUDACXX_NODEBUG = typename _If< +# ifdef _LIBCUDACXX_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT + false && +# endif + _LIBCUDACXX_TRAIT(is_arithmetic, _Dest), + __narrowing_check, + __no_narrowing_check>::template _Apply<_Dest, _Source>; template -struct __overload { +struct __overload +{ template - auto operator()(_Tp, _Up&&) const -> __check_for_narrowing<_Tp, _Up>; + _LIBCUDACXX_INLINE_VISIBILITY auto operator()(_Tp, _Up&&) const -> __check_for_narrowing<_Tp, _Up>; }; template -struct __overload_bool { +struct __overload_bool +{ template > - auto operator()(bool, _Up&&) const - -> enable_if_t, __type_identity<_Tp>>; + _LIBCUDACXX_INLINE_VISIBILITY auto operator()(bool, _Up&&) const + -> enable_if_t<_LIBCUDACXX_TRAIT(is_same, _Ap, bool), __type_identity<_Tp>>; }; template -struct __overload : __overload_bool {}; +struct __overload : __overload_bool +{}; template -struct __overload : __overload_bool {}; +struct __overload : __overload_bool +{}; template -struct __overload : __overload_bool {}; +struct __overload : __overload_bool +{}; template -struct __overload : __overload_bool {}; - -template -struct __all_overloads : _Bases... { - void operator()() const; +struct __overload : __overload_bool +{}; + +# if _LIBCUDACXX_STD_VER > 14 +template +struct __all_overloads : _Bases... +{ + _LIBCUDACXX_INLINE_VISIBILITY void operator()() const; using _Bases::operator()...; }; +# else +template +struct __all_overloads; + +template +struct __all_overloads<_Head, _Next, _Bases...> + : _Head + , __all_overloads<_Next, _Bases...> +{ + using _Head::operator(); + using __all_overloads<_Next, _Bases...>::operator(); +}; + +template +struct __all_overloads<_Only> : _Only +{ + using _Only::operator(); +}; +# endif template struct __make_overloads_imp; -template -struct __make_overloads_imp<__tuple_indices<_Idx...> > { - template - using _Apply _LIBCUDACXX_NODEBUG_TYPE = __all_overloads<__overload<_Types, _Idx>...>; +template +struct __make_overloads_imp<__tuple_indices<_Idx...>> +{ + template + using _Apply _LIBCUDACXX_NODEBUG = __all_overloads<__overload<_Types, _Idx>...>; }; -template -using _MakeOverloads _LIBCUDACXX_NODEBUG_TYPE = typename __make_overloads_imp< - __make_indices_imp >::template _Apply<_Types...>; +template +using _MakeOverloads _LIBCUDACXX_NODEBUG = + typename __make_overloads_imp<__make_indices_imp>::template _Apply<_Types...>; template -using __best_match_t = - typename invoke_result_t<_MakeOverloads<_Types...>, _Tp, _Tp>::type; +using __best_match_t = typename invoke_result_t<_MakeOverloads<_Types...>, _Tp, _Tp>::type; + +struct __invalid_variant_constraints +{ + static constexpr bool __constructible = false; + static constexpr bool __nothrow_constructible = false; + static constexpr bool __assignable = false; + static constexpr bool __nothrow_assignable = false; +}; + +template +struct __variant_constraints +{ + template > + struct __match_construct + { + static constexpr size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value; + + static constexpr bool __constructible = _LIBCUDACXX_TRAIT(is_constructible, _Tp, _Arg); + static constexpr bool __nothrow_constructible = _LIBCUDACXX_TRAIT(is_nothrow_constructible, _Tp, _Arg); + }; + + template + struct __variadic_construct + { + using _Tp = variant_alternative_t<_Ip, variant<_Types...>>; + + static constexpr bool __constructible = _LIBCUDACXX_TRAIT(is_constructible, _Tp, _Args...); + static constexpr bool __nothrow_constructible = _LIBCUDACXX_TRAIT(is_nothrow_constructible, _Tp, _Args...); + }; + + template + struct __variadic_ilist_construct + { + using _Tp = variant_alternative_t<_Ip, variant<_Types...>>; + + static constexpr bool __constructible = _LIBCUDACXX_TRAIT(is_constructible, _Tp, initializer_list<_Up>&, _Args...); + static constexpr bool __nothrow_constructible = + _LIBCUDACXX_TRAIT(is_nothrow_constructible, _Tp, initializer_list<_Up>&, _Args...); + }; + + template > + struct __match_assign + { + static constexpr size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value; -} // __variant_detail + static constexpr bool __assignable = + _LIBCUDACXX_TRAIT(is_assignable, _Tp&, _Arg) && _LIBCUDACXX_TRAIT(is_constructible, _Tp, _Arg); + static constexpr bool __nothrow_assignable = + _LIBCUDACXX_TRAIT(is_nothrow_assignable, _Tp&, _Arg) && _LIBCUDACXX_TRAIT(is_nothrow_constructible, _Tp, _Arg); + }; + + template + struct __swappable + { + static constexpr bool __is_swappable = + __all<(_LIBCUDACXX_TRAIT(is_move_constructible, _Types) && _LIBCUDACXX_TRAIT(is_swappable, _Types))...>::value; + + static constexpr bool __is_nothrow_swappable = + __all<(_LIBCUDACXX_TRAIT(is_nothrow_move_constructible, _Types) + && _LIBCUDACXX_TRAIT(is_nothrow_swappable, _Types))...>::value; + }; +}; +} // namespace __variant_detail template class _LIBCUDACXX_TEMPLATE_VIS variant - : private __sfinae_ctor_base< - __all...>::value, - __all...>::value>, - private __sfinae_assign_base< - __all<(is_copy_constructible_v<_Types> && - is_copy_assignable_v<_Types>)...>::value, - __all<(is_move_constructible_v<_Types> && - is_move_assignable_v<_Types>)...>::value> { - static_assert(0 < sizeof...(_Types), - "variant must consist of at least one alternative."); - - static_assert(__all...>::value, + : private __sfinae_ctor_base<__all<_LIBCUDACXX_TRAIT(is_copy_constructible, _Types)...>::value, + __all<_LIBCUDACXX_TRAIT(is_move_constructible, _Types)...>::value> + , private __sfinae_assign_base<__all<(_LIBCUDACXX_TRAIT(is_copy_constructible, _Types) + && _LIBCUDACXX_TRAIT(is_copy_assignable, _Types))...>::value, + __all<(_LIBCUDACXX_TRAIT(is_move_constructible, _Types) + && _LIBCUDACXX_TRAIT(is_move_assignable, _Types))...>::value> +{ + static_assert(0 < sizeof...(_Types), "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, + static_assert(__all::value, "variant can not have a reference type as an alternative."); - static_assert(__all...>::value, + static_assert(__all::value, "variant can not have a void type as an alternative."); - using __first_type = variant_alternative_t<0, variant>; + using __first_type = variant_alternative_t<0, variant>; + using __constraints = __variant_detail::__variant_constraints<_Types...>; public: + // Needs to be dependent to guard against incomplete types template , - _Dummy>::value, - int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr variant() noexcept(is_nothrow_default_constructible_v<__first_type>) - : __impl(in_place_index<0>) {} - - variant(const variant&) = default; - variant(variant&&) = default; - - template < - class _Arg, - enable_if_t, variant>, int> = 0, - enable_if_t>::value, int> = 0, - enable_if_t>::value, int> = 0, - class _Tp = __variant_detail::__best_match_t<_Arg, _Types...>, - size_t _Ip = - __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, - enable_if_t, int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr variant(_Arg&& __arg) noexcept( - is_nothrow_constructible_v<_Tp, _Arg>) - : __impl(in_place_index<_Ip>, _CUDA_VSTD::forward<_Arg>(__arg)) {} - - template , - class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, - enable_if_t, int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - explicit constexpr variant( - in_place_index_t<_Ip>, - _Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, _Args...>) - : __impl(in_place_index<_Ip>, _CUDA_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> - inline _LIBCUDACXX_INLINE_VISIBILITY - 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, _CUDA_VSTD::forward<_Args>(__args)...) {} - - template < - class _Tp, - class... _Args, - size_t _Ip = - __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, - enable_if_t, int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - explicit constexpr variant(in_place_type_t<_Tp>, _Args&&... __args) noexcept( - is_nothrow_constructible_v<_Tp, _Args...>) - : __impl(in_place_index<_Ip>, _CUDA_VSTD::forward<_Args>(__args)...) {} - - template < - class _Tp, - class _Up, - class... _Args, - size_t _Ip = - __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, - enable_if_t&, _Args...>, - int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - 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, _CUDA_VSTD::forward<_Args>(__args)...) {} - - ~variant() = default; - - variant& operator=(const variant&) = default; - variant& operator=(variant&&) = default; - - template < - class _Arg, - enable_if_t, variant>, int> = 0, - class _Tp = __variant_detail::__best_match_t<_Arg, _Types...>, - size_t _Ip = - __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, - enable_if_t && is_constructible_v<_Tp, _Arg>, - int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - variant& operator=(_Arg&& __arg) noexcept( - is_nothrow_assignable_v<_Tp&, _Arg> && - is_nothrow_constructible_v<_Tp, _Arg>) { - __impl.template __assign<_Ip>(_CUDA_VSTD::forward<_Arg>(__arg)); + class = enable_if_t<__dependent_type, _Dummy>::value>> + _LIBCUDACXX_INLINE_VISIBILITY constexpr variant() noexcept( + _LIBCUDACXX_TRAIT(is_nothrow_default_constructible, __first_type)) + : __impl_(in_place_index<0>) + {} + + _LIBCUDACXX_HIDE_FROM_ABI constexpr variant(const variant&) = default; + _LIBCUDACXX_HIDE_FROM_ABI constexpr variant(variant&&) = default; + + template + using __match_construct = + _If, variant) + && !__is_inplace_type<__remove_cvref_t<_Arg>>::value // + && !__is_inplace_index<__remove_cvref_t<_Arg>>::value, + typename __constraints::template __match_construct<_Arg>, + __variant_detail::__invalid_variant_constraints>; + + // CTAD fails if we do not SFINAE the empty variant away first + template , + class _Constraints = __match_construct<_Arg>, + class = enable_if_t<_Constraints::__constructible>> + _LIBCUDACXX_INLINE_VISIBILITY constexpr variant(_Arg&& __arg) noexcept(_Constraints::__nothrow_constructible) + : __impl_(in_place_index<_Constraints::_Ip>, _CUDA_VSTD::forward<_Arg>(__arg)) + {} + + template + using __variadic_construct = + _If<(_Ip < sizeof...(_Types)), + typename __constraints::template __variadic_construct<_Ip, _Args...>, + __variant_detail::__invalid_variant_constraints>; + + template , + class = enable_if_t<_Constraints::__constructible>> + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr variant(in_place_index_t<_Ip>, _Args&&... __args) noexcept( + _Constraints::__nothrow_constructible) + : __impl_(in_place_index<_Ip>, _CUDA_VSTD::forward<_Args>(__args)...) + {} + + template + using __variadic_ilist_construct = + _If<(_Ip < sizeof...(_Types)), + typename __constraints::template __variadic_ilist_construct<_Ip, _Up, _Args...>, + __variant_detail::__invalid_variant_constraints>; + + template , + class = enable_if_t<_Constraints::__constructible>> + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr variant( + in_place_index_t<_Ip>, initializer_list<_Up> __il, _Args&&... __args) noexcept(_Constraints::__nothrow_constructible) + : __impl_(in_place_index<_Ip>, __il, _CUDA_VSTD::forward<_Args>(__args)...) + {} + + template ::value, + class _Constraints = __variadic_construct<_Ip, _Args...>, + class = enable_if_t<_Constraints::__constructible>> + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr variant(in_place_type_t<_Tp>, _Args&&... __args) noexcept( + _Constraints::__nothrow_constructible) + : __impl_(in_place_index<_Ip>, _CUDA_VSTD::forward<_Args>(__args)...) + {} + + template ::value, + class _Constraints = __variadic_ilist_construct<_Ip, _Up, _Args...>, + class = enable_if_t<_Constraints::__constructible>> + _LIBCUDACXX_INLINE_VISIBILITY explicit constexpr variant( + in_place_type_t<_Tp>, initializer_list<_Up> __il, _Args&&... __args) noexcept(_Constraints::__nothrow_constructible) + : __impl_(in_place_index<_Ip>, __il, _CUDA_VSTD::forward<_Args>(__args)...) + {} + + _LIBCUDACXX_HIDE_FROM_ABI ~variant() = default; + + _LIBCUDACXX_HIDE_FROM_ABI constexpr variant& operator=(const variant&) = default; + _LIBCUDACXX_HIDE_FROM_ABI constexpr variant& operator=(variant&&) = default; + + template + using __match_assign = + _If, variant), + typename __constraints::template __match_assign<_Arg>, + __variant_detail::__invalid_variant_constraints>; + + template , class = enable_if_t<_Constraints::__assignable>> + _LIBCUDACXX_INLINE_VISIBILITY variant& operator=(_Arg&& __arg) noexcept(_Constraints::__nothrow_assignable) + { + __impl_.template __assign<_Constraints::_Ip>(_CUDA_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> - inline _LIBCUDACXX_INLINE_VISIBILITY - _Tp& emplace(_Args&&... __args) { - return __impl.template __emplace<_Ip>(_CUDA_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> - inline _LIBCUDACXX_INLINE_VISIBILITY - _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { - return __impl.template __emplace<_Ip>(__il, _CUDA_VSTD::forward<_Args>(__args)...); - } - - template < - class _Tp, - class... _Args, - size_t _Ip = - __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, - enable_if_t, int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - _Tp& emplace(_Args&&... __args) { - return __impl.template __emplace<_Ip>(_CUDA_VSTD::forward<_Args>(__args)...); - } - - template < - class _Tp, - class _Up, - class... _Args, - size_t _Ip = - __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, - enable_if_t&, _Args...>, - int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { - return __impl.template __emplace<_Ip>(__il, _CUDA_VSTD::forward<_Args>(__args)...); - } - - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr bool valueless_by_exception() const noexcept { - return __impl.valueless_by_exception(); - } - - inline _LIBCUDACXX_INLINE_VISIBILITY - constexpr size_t index() const noexcept { return __impl.index(); } - - template < - bool _Dummy = true, - enable_if_t< - __all<( - __dependent_type, _Dummy>::value && - __dependent_type, _Dummy>::value)...>::value, - int> = 0> - inline _LIBCUDACXX_INLINE_VISIBILITY - void swap(variant& __that) noexcept( - __all<(is_nothrow_move_constructible_v<_Types> && - is_nothrow_swappable_v<_Types>)...>::value) { - __impl.__swap(__that.__impl); + template , + class = enable_if_t<_Constraints::__constructible>> + _LIBCUDACXX_INLINE_VISIBILITY typename _Constraints::_Tp& emplace(_Args&&... __args) + { + return __impl_.template __emplace<_Ip>(_CUDA_VSTD::forward<_Args>(__args)...); + } + + template , + class = enable_if_t<_Constraints::__constructible>> + _LIBCUDACXX_INLINE_VISIBILITY typename _Constraints::_Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) + { + return __impl_.template __emplace<_Ip>(__il, _CUDA_VSTD::forward<_Args>(__args)...); + } + + template ::value, + enable_if_t<_LIBCUDACXX_TRAIT(is_constructible, _Tp, _Args...), int> = 0> + _LIBCUDACXX_INLINE_VISIBILITY _Tp& emplace(_Args&&... __args) + { + return __impl_.template __emplace<_Ip>(_CUDA_VSTD::forward<_Args>(__args)...); + } + + template ::value, + enable_if_t<_LIBCUDACXX_TRAIT(is_constructible, _Tp, initializer_list<_Up>&, _Args...), int> = 0> + _LIBCUDACXX_INLINE_VISIBILITY _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) + { + return __impl_.template __emplace<_Ip>(__il, _CUDA_VSTD::forward<_Args>(__args)...); + } + + _LIBCUDACXX_INLINE_VISIBILITY constexpr bool valueless_by_exception() const noexcept + { + return __impl_.valueless_by_exception(); + } + + _LIBCUDACXX_INLINE_VISIBILITY constexpr size_t index() const noexcept + { + return __impl_.index(); + } + + // Needs to be dependent to guard against incomplete types + template + using __swap_constraint = + __dependent_type::template __swappable<_Dummy>, _Dummy>; + + template , + class = enable_if_t<_Constraint::__is_swappable>> + _LIBCUDACXX_INLINE_VISIBILITY void swap(variant& __that) noexcept(_Constraint::__is_nothrow_swappable) + { + __impl_.__swap(__that.__impl_); + } + + _LIBCUDACXX_INLINE_VISIBILITY static constexpr size_t __size() noexcept + { + return sizeof...(_Types); } private: - __variant_detail::__impl<_Types...> __impl; + __variant_detail::__impl<_Types...> __impl_; friend struct __variant_detail::__access::__variant; friend struct __variant_detail::__visitation::__variant; }; template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept { +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept +{ return __v.index() == _Ip; } template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { - return __holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept +{ + return _CUDA_VSTD::__holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -constexpr auto&& __generic_get(_Vp&& __v) { +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr auto&& __generic_get(_Vp&& __v) +{ using __variant_detail::__access::__variant; - if (!__holds_alternative<_Ip>(__v)) { + if (!_CUDA_VSTD::__holds_alternative<_Ip>(__v)) + { __throw_bad_variant_access(); } return __variant::__get_alt<_Ip>(_CUDA_VSTD::forward<_Vp>(__v)).__value; } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -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); +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr variant_alternative_t< + _Ip, + variant<_Types...>>& +get(variant<_Types...>& __v) +{ + static_assert(_Ip < sizeof...(_Types), ""); + static_assert(!_LIBCUDACXX_TRAIT(is_void, variant_alternative_t<_Ip, variant<_Types...>>), ""); + return _CUDA_VSTD::__generic_get<_Ip>(__v); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -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>(_CUDA_VSTD::move(__v)); +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr variant_alternative_t< + _Ip, + variant<_Types...>>&& +get(variant<_Types...>&& __v) +{ + static_assert(_Ip < sizeof...(_Types), ""); + static_assert(!_LIBCUDACXX_TRAIT(is_void, variant_alternative_t<_Ip, variant<_Types...>>), ""); + return _CUDA_VSTD::__generic_get<_Ip>(_CUDA_VSTD::move(__v)); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -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); +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr const variant_alternative_t< + _Ip, + variant<_Types...>>& +get(const variant<_Types...>& __v) +{ + static_assert(_Ip < sizeof...(_Types), ""); + static_assert(!_LIBCUDACXX_TRAIT(is_void, variant_alternative_t<_Ip, variant<_Types...>>), ""); + return _CUDA_VSTD::__generic_get<_Ip>(__v); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -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>(_CUDA_VSTD::move(__v)); +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr const variant_alternative_t< + _Ip, + variant<_Types...>>&& +get(const variant<_Types...>&& __v) +{ + static_assert(_Ip < sizeof...(_Types), ""); + static_assert(!_LIBCUDACXX_TRAIT(is_void, variant_alternative_t<_Ip, variant<_Types...>>), ""); + return _CUDA_VSTD::__generic_get<_Ip>(_CUDA_VSTD::move(__v)); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -constexpr _Tp& get(variant<_Types...>& __v) { - static_assert(!is_void_v<_Tp>); +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Tp& +get(variant<_Types...>& __v) +{ + static_assert(!_LIBCUDACXX_TRAIT(is_void, _Tp), ""); return _CUDA_VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -constexpr _Tp&& get(variant<_Types...>&& __v) { - static_assert(!is_void_v<_Tp>); - return _CUDA_VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>( - _CUDA_VSTD::move(__v)); +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Tp&& +get(variant<_Types...>&& __v) +{ + static_assert(!_LIBCUDACXX_TRAIT(is_void, _Tp), ""); + return _CUDA_VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>(_CUDA_VSTD::move(__v)); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -constexpr const _Tp& get(const variant<_Types...>& __v) { - static_assert(!is_void_v<_Tp>); +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr const _Tp& +get(const variant<_Types...>& __v) +{ + static_assert(!_LIBCUDACXX_TRAIT(is_void, _Tp), ""); return _CUDA_VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -constexpr const _Tp&& get(const variant<_Types...>&& __v) { - static_assert(!is_void_v<_Tp>); - return _CUDA_VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>( - _CUDA_VSTD::move(__v)); +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr const _Tp&& +get(const variant<_Types...>&& __v) +{ + static_assert(!_LIBCUDACXX_TRAIT(is_void, _Tp), ""); + return _CUDA_VSTD::get<__find_exactly_one_t<_Tp, _Types...>::value>(_CUDA_VSTD::move(__v)); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr auto* __generic_get_if(_Vp* __v) noexcept { +_LIBCUDACXX_INLINE_VISIBILITY constexpr auto* __generic_get_if(_Vp* __v) noexcept +{ using __variant_detail::__access::__variant; - return __v && __holds_alternative<_Ip>(*__v) - ? _CUDA_VSTD::addressof(__variant::__get_alt<_Ip>(*__v).__value) - : nullptr; + return __v && _CUDA_VSTD::__holds_alternative<_Ip>(*__v) + ? _CUDA_VSTD::addressof(__variant::__get_alt<_Ip>(*__v).__value) + : nullptr; } template -inline _LIBCUDACXX_INLINE_VISIBILITY -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); +_LIBCUDACXX_INLINE_VISIBILITY constexpr add_pointer_t>> +get_if(variant<_Types...>* __v) noexcept +{ + static_assert(_Ip < sizeof...(_Types), ""); + static_assert(!_LIBCUDACXX_TRAIT(is_void, variant_alternative_t<_Ip, variant<_Types...>>), ""); + return _CUDA_VSTD::__generic_get_if<_Ip>(__v); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -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); +_LIBCUDACXX_INLINE_VISIBILITY constexpr add_pointer_t>> +get_if(const variant<_Types...>* __v) noexcept +{ + static_assert(_Ip < sizeof...(_Types), ""); + static_assert(!_LIBCUDACXX_TRAIT(is_void, variant_alternative_t<_Ip, variant<_Types...>>), ""); + return _CUDA_VSTD::__generic_get_if<_Ip>(__v); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr add_pointer_t<_Tp> -get_if(variant<_Types...>* __v) noexcept { - static_assert(!is_void_v<_Tp>); +_LIBCUDACXX_INLINE_VISIBILITY constexpr add_pointer_t<_Tp> get_if(variant<_Types...>* __v) noexcept +{ + static_assert(!_LIBCUDACXX_TRAIT(is_void, _Tp), ""); return _CUDA_VSTD::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr add_pointer_t -get_if(const variant<_Types...>* __v) noexcept { - static_assert(!is_void_v<_Tp>); +_LIBCUDACXX_INLINE_VISIBILITY constexpr add_pointer_t get_if(const variant<_Types...>* __v) noexcept +{ + static_assert(!_LIBCUDACXX_TRAIT(is_void, _Tp), ""); return _CUDA_VSTD::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -struct __convert_to_bool { +struct __convert_to_bool +{ template - _LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator()(_T1 && __t1, _T2&& __t2) const { - static_assert(std::is_convertible(__t1), _CUDA_VSTD::forward<_T2>(__t2))), bool>::value, - "the relational operator does not return a type which is implicitly convertible to bool"); + _LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator()(_T1&& __t1, _T2&& __t2) const + { + static_assert( + _LIBCUDACXX_TRAIT( + is_convertible, decltype(_Operator{}(_CUDA_VSTD::forward<_T1>(__t1), _CUDA_VSTD::forward<_T2>(__t2))), bool), + "the relational operator does not return a type which is " + "implicitly convertible to bool"); return _Operator{}(_CUDA_VSTD::forward<_T1>(__t1), _CUDA_VSTD::forward<_T2>(__t2)); } }; +struct __variant_binary_visitor +{ + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto + __visit(const size_t __index, _BinaryOp&& __op, const _LeftVariant& __lhs, const _RightVariant& __rhs) + { + return __visit(integral_constant - 1>{}, + __index, + _CUDA_VSTD::forward<_BinaryOp>(__op), + __lhs, + __rhs); + } + +private: + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto + __visit(integral_constant, + const size_t __index, + _BinaryOp&& __op, + const _LeftVariant& __lhs, + const _RightVariant& __rhs) + { + if (__index == _CurrentIndex) + { + return __op(_CUDA_VSTD::get<_CurrentIndex>(__lhs), _CUDA_VSTD::get<_CurrentIndex>(__rhs)); + } + return __visit( + integral_constant{}, __index, _CUDA_VSTD::forward<_BinaryOp>(__op), __lhs, __rhs); + } + + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static constexpr auto + __visit(integral_constant, + const size_t __index, + _BinaryOp&& __op, + const _LeftVariant& __lhs, + const _RightVariant& __rhs) + { + if (__index == 0) + { + return __op(_CUDA_VSTD::get<0>(__lhs), _CUDA_VSTD::get<0>(__rhs)); + } + // We already checked that every variant has a value, so we should never reach this line + _LIBCUDACXX_UNREACHABLE(); + } +}; + template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator==(const variant<_Types...>& __lhs, - const variant<_Types...>& __rhs) { - using __variant_detail::__visitation::__variant; - if (__lhs.index() != __rhs.index()) return false; - if (__lhs.valueless_by_exception()) return true; - return __variant::__visit_value_at(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); +_LIBCUDACXX_INLINE_VISIBILITY constexpr bool operator==(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) +{ + const auto __index = __lhs.index(); + if (__index != __rhs.index()) + { + return false; + } + if (__lhs.valueless_by_exception()) + { + return true; + } + + return __variant_binary_visitor::__visit(__index, __convert_to_bool>{}, __lhs, __rhs); } +# ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR + template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator!=(const variant<_Types...>& __lhs, - const variant<_Types...>& __rhs) { - using __variant_detail::__visitation::__variant; - if (__lhs.index() != __rhs.index()) return true; - if (__lhs.valueless_by_exception()) return false; - return __variant::__visit_value_at( - __lhs.index(), __convert_to_bool>{}, __lhs, __rhs); + requires(three_way_comparable<_Types> && ...) +_LIBCUDACXX_INLINE_VISIBILITY constexpr common_comparison_category_t...> +operator<=>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) +{ + using __result_t = common_comparison_category_t...>; + if (__lhs.valueless_by_exception() && __rhs.valueless_by_exception()) + { + return strong_ordering::equal; + } + if (__lhs.valueless_by_exception()) + { + return strong_ordering::less; + } + if (__rhs.valueless_by_exception()) + { + return strong_ordering::greater; + } + if (auto __c = __lhs.index() <=> __rhs.index(); __c != 0) + { + return __c; + } + auto __three_way = [](const _Type& __v, const _Type& __w) -> __result_t { + return __v <=> __w; + }; + return __variant_binary_visitor::__visit(__lhs.index(), __three_way, __lhs, __rhs); } +# endif // !_LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR + template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator<(const variant<_Types...>& __lhs, - const variant<_Types...>& __rhs) { - using __variant_detail::__visitation::__variant; - 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::__visit_value_at(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); +_LIBCUDACXX_INLINE_VISIBILITY 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_binary_visitor::__visit(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator>(const variant<_Types...>& __lhs, - const variant<_Types...>& __rhs) { - using __variant_detail::__visitation::__variant; - 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::__visit_value_at(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); +_LIBCUDACXX_INLINE_VISIBILITY 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_binary_visitor::__visit(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator<=(const variant<_Types...>& __lhs, - const variant<_Types...>& __rhs) { - using __variant_detail::__visitation::__variant; - 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::__visit_value_at( - __lhs.index(), __convert_to_bool>{}, __lhs, __rhs); +_LIBCUDACXX_INLINE_VISIBILITY 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_binary_visitor::__visit(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } template -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator>=(const variant<_Types...>& __lhs, - const variant<_Types...>& __rhs) { - using __variant_detail::__visitation::__variant; - 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::__visit_value_at( - __lhs.index(), __convert_to_bool>{}, __lhs, __rhs); +_LIBCUDACXX_INLINE_VISIBILITY 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_binary_visitor::__visit(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } -template -inline _LIBCUDACXX_INLINE_VISIBILITY -_LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { - using __variant_detail::__visitation::__variant; - bool __results[] = {__vs.valueless_by_exception()...}; - for (bool __result : __results) { - if (__result) { - __throw_bad_variant_access(); - } +template +_LIBCUDACXX_INLINE_VISIBILITY 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; } - return __variant::__visit_value(_CUDA_VSTD::forward<_Visitor>(__visitor), - _CUDA_VSTD::forward<_Vs>(__vs)...); + if (__lhs.index() > __rhs.index()) + { + return true; + } + if (__lhs.index() < __rhs.index()) + { + return false; + } + return __variant_binary_visitor::__visit(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } -struct _LIBCUDACXX_TEMPLATE_VIS monostate {}; - -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator<(monostate, monostate) noexcept { return false; } - -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator>(monostate, monostate) noexcept { return false; } - -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator<=(monostate, monostate) noexcept { return true; } - -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator>=(monostate, monostate) noexcept { return true; } +template +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void +__throw_if_valueless(_Vs&&... __vs) +{ + int __unused[] = { + (_CUDA_VSTD::__as_variant(__vs).valueless_by_exception() ? __throw_bad_variant_access() : void(), 0)..., 0}; + (void) __unused[0]; +} -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator==(monostate, monostate) noexcept { return true; } +template ()))...>> +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) +visit(_Visitor&& __visitor, _Vs&&... __vs) +{ + using __variant_detail::__visitation::__variant; + _CUDA_VSTD::__throw_if_valueless(_CUDA_VSTD::forward<_Vs>(__vs)...); + return __variant::__visit_value(_CUDA_VSTD::forward<_Visitor>(__visitor), _CUDA_VSTD::forward<_Vs>(__vs)...); +} -inline _LIBCUDACXX_INLINE_VISIBILITY -constexpr bool operator!=(monostate, monostate) noexcept { return false; } +template ()))...>> +_LIBCUDACXX_INLINE_VISIBILITY _LIBCUDACXX_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp +visit(_Visitor&& __visitor, _Vs&&... __vs) +{ + using __variant_detail::__visitation::__variant; + _CUDA_VSTD::__throw_if_valueless(_CUDA_VSTD::forward<_Vs>(__vs)...); + return __variant::__visit_value<_Rp>(_CUDA_VSTD::forward<_Visitor>(__visitor), _CUDA_VSTD::forward<_Vs>(__vs)...); +} template -inline _LIBCUDACXX_INLINE_VISIBILITY -auto swap(variant<_Types...>& __lhs, - variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs))) - -> decltype(__lhs.swap(__rhs)) { - __lhs.swap(__rhs); +_LIBCUDACXX_INLINE_VISIBILITY auto +swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs))) + -> decltype(__lhs.swap(__rhs)) +{ + return __lhs.swap(__rhs); } +# ifndef __cuda_std__ template -struct _LIBCUDACXX_TEMPLATE_VIS hash< - __enable_hash_helper, remove_const_t<_Types>...>> { +struct _LIBCUDACXX_TEMPLATE_VIS hash<__enable_hash_helper, remove_const_t<_Types>...>> +{ using argument_type = variant<_Types...>; - using result_type = size_t; - - inline _LIBCUDACXX_INLINE_VISIBILITY - result_type operator()(const argument_type& __v) const { - using __variant_detail::__visitation::__variant; - size_t __res = - __v.valueless_by_exception() - ? 299792458 // Random value chosen by the universe upon creation - : __variant::__visit_alt( - [](const auto& __alt) { - using __alt_type = __remove_cvref_t; - using __value_type = remove_const_t< - typename __alt_type::__value_type>; - return hash<__value_type>{}(__alt.__value); - }, - __v); - return __hash_combine(__res, hash{}(__v.index())); + using result_type = size_t; + + template + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static size_t + __hash(integral_constant, const size_t __index, const argument_type& __v) noexcept + { + if (__index == _CurrentIndex) + { + using __value_type = remove_const_t<__type_pack_element<_CurrentIndex, _Types...>>; + return hash<__value_type>{}(__access::__base::__get_alt<_CurrentIndex>(this->__as_base()).__value); + } + __hash(integral_constant{}, __index, __v); + } + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY static size_t + __hash(integral_constant, const size_t __index, const argument_type& __v) noexcept + { + if (__index == 0) + { + using __value_type = remove_const_t<__type_pack_element<0, _Types...>>; + return hash<__value_type>{}(__access::__base::__get_alt<0>(this->__as_base()).__value); + } + // We already checked that every variant has a value, so we should never reach this line + _LIBCUDACXX_UNREACHABLE(); } -}; - -template <> -struct _LIBCUDACXX_TEMPLATE_VIS hash { - using argument_type = monostate; - using result_type = size_t; - inline _LIBCUDACXX_INLINE_VISIBILITY - result_type operator()(const argument_type&) const noexcept { - return 66740831; // return a fundamentally attractive random value. + inline _LIBCUDACXX_HIDDEN _LIBCUDACXX_INLINE_VISIBILITY result_type operator()(const argument_type& __v) const + { + size_t __res = __v.valueless_by_exception() + ? 299792458 // Random value chosen by the universe upon creation + : __hash(integral_constant{}, __v.index(), __v); + return _CUDA_VSTD::__hash_combine(__res, hash{}(__v.index())); } }; +# endif // __cuda_std__ + +// __unchecked_get is the same as _CUDA_VSTD::get, except, it is UB to use it +// with the wrong type whereas _CUDA_VSTD::get will throw or returning nullptr. +// This makes it faster than _CUDA_VSTD::get. +template +_LIBCUDACXX_INLINE_VISIBILITY constexpr auto&& __unchecked_get(_Vp&& __v) noexcept +{ + using __variant_detail::__access::__variant; + return __variant::__get_alt<_Ip>(_CUDA_VSTD::forward<_Vp>(__v)).__value; +} -#endif // _LIBCUDACXX_STD_VER > 14 +template +_LIBCUDACXX_INLINE_VISIBILITY constexpr auto&& __unchecked_get(const variant<_Types...>& __v) noexcept +{ + return _CUDA_VSTD::__unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} + +template +_LIBCUDACXX_INLINE_VISIBILITY constexpr auto&& __unchecked_get(variant<_Types...>& __v) noexcept +{ + return _CUDA_VSTD::__unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); +} _LIBCUDACXX_END_NAMESPACE_STD -_LIBCUDACXX_POP_MACROS +#endif // _LIBCUDACXX_STD_VER >= 14 -#endif // _LIBCUDACXX_VARIANT +#endif // _LIBCUDACXX_VARIANT diff --git a/libcudacxx/include/cuda/std/variant b/libcudacxx/include/cuda/std/variant new file mode 100644 index 0000000000..c5d490311b --- /dev/null +++ b/libcudacxx/include/cuda/std/variant @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// Part of libcu++, the C++ Standard Library for your entire system, +// under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _CUDA_STD_VARIANT +#define _CUDA_STD_VARIANT + +#include "detail/__config" + +#include "detail/__pragma_push" + +#include "detail/libcxx/include/variant" + +#include "detail/__pragma_pop" + +#endif //_CUDA_STD_VARIANT diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp index 5caff3b1d1..0db55cf4eb 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,10 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// XFAIL: dylib-has-no-bad_variant_access +// UNSUPPORTED: c++03, c++11, c++14 +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.general/nothing_to_do.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.general/nothing_to_do.pass.cpp index 8002e55766..796f3c353b 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.general/nothing_to_do.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.general/nothing_to_do.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_if_index.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_if_index.pass.cpp index 827f7a23e9..3333d2a993 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_if_index.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_if_index.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_if_type.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_if_type.pass.cpp index 341d53906b..b81e000f5b 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_if_type.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_if_type.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_index.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_index.pass.cpp index 16e2f209ce..b18d94fb0c 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_index.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_index.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // @@ -38,11 +38,7 @@ void test_const_lvalue_get() { { using V = std::variant; constexpr V v(42); -#ifdef TEST_WORKAROUND_CONSTEXPR_IMPLIES_NOEXCEPT - ASSERT_NOEXCEPT(std::get<0>(v)); -#else ASSERT_NOT_NOEXCEPT(std::get<0>(v)); -#endif ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int &); static_assert(std::get<0>(v) == 42, ""); } @@ -56,11 +52,7 @@ void test_const_lvalue_get() { { using V = std::variant; constexpr V v(42l); -#ifdef TEST_WORKAROUND_CONSTEXPR_IMPLIES_NOEXCEPT - ASSERT_NOEXCEPT(std::get<1>(v)); -#else ASSERT_NOT_NOEXCEPT(std::get<1>(v)); -#endif ASSERT_SAME_TYPE(decltype(std::get<1>(v)), const long &); static_assert(std::get<1>(v) == 42, ""); } diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_type.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_type.pass.cpp index 333f3d9103..dc938d16a8 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_type.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/get_type.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // @@ -32,11 +32,7 @@ void test_const_lvalue_get() { { using V = std::variant; constexpr V v(42); -#ifdef TEST_WORKAROUND_CONSTEXPR_IMPLIES_NOEXCEPT - ASSERT_NOEXCEPT(std::get(v)); -#else ASSERT_NOT_NOEXCEPT(std::get(v)); -#endif ASSERT_SAME_TYPE(decltype(std::get(v)), const int &); static_assert(std::get(v) == 42, ""); } @@ -50,11 +46,7 @@ void test_const_lvalue_get() { { using V = std::variant; constexpr V v(42l); -#ifdef TEST_WORKAROUND_CONSTEXPR_IMPLIES_NOEXCEPT - ASSERT_NOEXCEPT(std::get(v)); -#else ASSERT_NOT_NOEXCEPT(std::get(v)); -#endif ASSERT_SAME_TYPE(decltype(std::get(v)), const long &); static_assert(std::get(v) == 42, ""); } diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/holds_alternative.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/holds_alternative.pass.cpp index b37462069d..9fd38222f8 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.get/holds_alternative.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.get/holds_alternative.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.hash/enabled_hash.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.hash/enabled_hash.pass.cpp index f5e0fbe117..ea120bf972 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.hash/enabled_hash.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.hash/enabled_hash.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.hash/hash.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.hash/hash.pass.cpp index a4255188ed..770bbecd73 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.hash/hash.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.hash/hash.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_alternative.fail.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_alternative.fail.cpp index 48d5e14e26..934d047338 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_alternative.fail.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_alternative.fail.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp index e8b6302c19..f5e1e3d2c9 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_size.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_size.pass.cpp index 654e5a9dfe..8c5b70d6f8 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_size.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.helpers/variant_size.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp index 255f6d0342..d4b9faff48 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // @@ -17,40 +16,33 @@ // constexpr bool operator>=(monostate, monostate) noexcept { return true; } // constexpr bool operator==(monostate, monostate) noexcept { return true; } // constexpr bool operator!=(monostate, monostate) noexcept { return false; } +// constexpr strong_ordering operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; } // since C++20 -#include "test_macros.h" #include -#include #include -int main(int, char**) { +#include "test_comparisons.h" +#include "test_macros.h" + +constexpr bool test() { using M = std::monostate; constexpr M m1{}; constexpr M m2{}; - { - static_assert((m1 < m2) == false, ""); - ASSERT_NOEXCEPT(m1 < m2); - } - { - static_assert((m1 > m2) == false, ""); - ASSERT_NOEXCEPT(m1 > m2); - } - { - static_assert((m1 <= m2) == true, ""); - ASSERT_NOEXCEPT(m1 <= m2); - } - { - static_assert((m1 >= m2) == true, ""); - ASSERT_NOEXCEPT(m1 >= m2); - } - { - static_assert((m1 == m2) == true, ""); - ASSERT_NOEXCEPT(m1 == m2); - } - { - static_assert((m1 != m2) == false, ""); - ASSERT_NOEXCEPT(m1 != m2); - } + assert(testComparisons6(m1, m2, /*isEqual*/ true, /*isLess*/ false)); + AssertComparisons6AreNoexcept(); + +// TODO: enable when is brought up to speed +#if TEST_STD_VER > 17 && false + assert(testOrder(m1, m2, std::strong_ordering::equal)); + AssertOrderAreNoexcept(); +#endif // TEST_STD_VER > 17 + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); return 0; } diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.monostate/monostate.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.monostate/monostate.pass.cpp index c726f684c3..9f62afda4b 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.monostate/monostate.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.monostate/monostate.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp index ed32215ffd..c1a5b8e474 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp index 8380c17e86..1cc4b87890 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp new file mode 100644 index 0000000000..f274546789 --- /dev/null +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp @@ -0,0 +1,195 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: true + +// + +// template class variant; + +// template requires (three_way_comparable && ...) +// constexpr std::common_comparison_category_t< +// std::compare_three_way_result_t...> +// operator<=>(const variant& t, const variant& u); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_comparisons.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +// MakeEmptyT throws in operator=(&&), so we can move to it to create valueless-by-exception variants. +struct MakeEmptyT { + MakeEmptyT() = default; + MakeEmptyT(MakeEmptyT&&) { throw 42; } + MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; } +}; +inline bool operator==(const MakeEmptyT&, const MakeEmptyT&) { + assert(false); + return false; +} +inline std::weak_ordering operator<=>(const MakeEmptyT&, const MakeEmptyT&) { + assert(false); + return std::weak_ordering::equivalent; +} + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place_type); + try { + v = std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} + +void test_empty() { + { + using V = std::variant; + V v1; + V v2; + makeEmpty(v2); + assert(testOrder(v1, v2, std::weak_ordering::greater)); + } + { + using V = std::variant; + V v1; + makeEmpty(v1); + V v2; + assert(testOrder(v1, v2, std::weak_ordering::less)); + } + { + using V = std::variant; + V v1; + makeEmpty(v1); + V v2; + makeEmpty(v2); + assert(testOrder(v1, v2, std::weak_ordering::equivalent)); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +template +constexpr bool test_with_types() { + using V = std::variant; + AssertOrderReturn(); + { // same index, same value + constexpr V v1(std::in_place_index<0>, T1{1}); + constexpr V v2(std::in_place_index<0>, T1{1}); + assert(testOrder(v1, v2, Order::equivalent)); + } + { // same index, value < other_value + constexpr V v1(std::in_place_index<0>, T1{0}); + constexpr V v2(std::in_place_index<0>, T1{1}); + assert(testOrder(v1, v2, Order::less)); + } + { // same index, value > other_value + constexpr V v1(std::in_place_index<0>, T1{1}); + constexpr V v2(std::in_place_index<0>, T1{0}); + assert(testOrder(v1, v2, Order::greater)); + } + { // LHS.index() < RHS.index() + constexpr V v1(std::in_place_index<0>, T1{0}); + constexpr V v2(std::in_place_index<1>, T2{0}); + assert(testOrder(v1, v2, Order::less)); + } + { // LHS.index() > RHS.index() + constexpr V v1(std::in_place_index<1>, T2{0}); + constexpr V v2(std::in_place_index<0>, T1{0}); + assert(testOrder(v1, v2, Order::greater)); + } + + return true; +} + +constexpr bool test_three_way() { + assert((test_with_types())); + assert((test_with_types())); + + { + using V = std::variant; + constexpr double nan = std::numeric_limits::quiet_NaN(); + { + constexpr V v1(std::in_place_type, 1); + constexpr V v2(std::in_place_type, nan); + assert(testOrder(v1, v2, std::partial_ordering::less)); + } + { + constexpr V v1(std::in_place_type, nan); + constexpr V v2(std::in_place_type, 2); + assert(testOrder(v1, v2, std::partial_ordering::greater)); + } + { + constexpr V v1(std::in_place_type, nan); + constexpr V v2(std::in_place_type, nan); + assert(testOrder(v1, v2, std::partial_ordering::unordered)); + } + } + + return true; +} + +// SFINAE tests +template +concept has_three_way_op = requires (T& t, U& u) { t <=> u; }; + +// std::three_way_comparable is a more stringent requirement that demands +// operator== and a few other things. +using std::three_way_comparable; + +struct HasSimpleOrdering { + constexpr bool operator==(const HasSimpleOrdering&) const; + constexpr bool operator<(const HasSimpleOrdering&) const; +}; + +struct HasOnlySpaceship { + constexpr bool operator==(const HasOnlySpaceship&) const = delete; + constexpr std::weak_ordering operator<=>(const HasOnlySpaceship&) const; +}; + +struct HasFullOrdering { + constexpr bool operator==(const HasFullOrdering&) const; + constexpr std::weak_ordering operator<=>(const HasFullOrdering&) const; +}; + +// operator<=> must resolve the return types of all its union types' +// operator<=>s to determine its own return type, so it is detectable by SFINAE +static_assert(!has_three_way_op); +static_assert(!has_three_way_op>); + +static_assert(!three_way_comparable); +static_assert(!three_way_comparable>); + +static_assert(has_three_way_op); +static_assert(!has_three_way_op>); + +static_assert(!three_way_comparable); +static_assert(!three_way_comparable>); + +static_assert( has_three_way_op); +static_assert( has_three_way_op>); + +static_assert( three_way_comparable); +static_assert( three_way_comparable>); + +int main(int, char**) { + test_three_way(); + static_assert(test_three_way()); + +#ifndef TEST_HAS_NO_EXCEPTIONS + test_empty(); +#endif // TEST_HAS_NO_EXCEPTIONS + + return 0; +} diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp index 087c574a49..e9afc215d6 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/implicit_ctad.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/implicit_ctad.pass.cpp new file mode 100644 index 0000000000..514c1f87fa --- /dev/null +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/implicit_ctad.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// + +// template class variant; + +// Make sure that the implicitly-generated CTAD works. + +// We make sure that it is not ill-formed, however we still produce a warning for +// this one because explicit construction from a variant using CTAD is ambiguous +// (in the sense that the programer intent is not clear). +// ADDITIONAL_COMPILE_FLAGS: -Wno-ctad-maybe-unsupported + +#include + +#include "test_macros.h" + +int main(int, char**) { + // This is the motivating example from P0739R0 + { + std::variant v1(3); + std::variant v2 = v1; + ASSERT_SAME_TYPE(decltype(v2), std::variant); + } + + { + std::variant v1(3); + std::variant v2 = std::variant(v1); // Technically valid, but intent is ambiguous! + ASSERT_SAME_TYPE(decltype(v2), std::variant); + } + + return 0; +} diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp index 3483298eda..bc52c9c545 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // @@ -211,16 +211,6 @@ void test_T_assignment_basic() { assert(v.index() == 1); assert(std::get<1>(v) == nullptr); } - { - std::variant v = 42; - v = false; - assert(v.index() == 0); - assert(!std::get<0>(v)); - bool lvt = true; - v = lvt; - assert(v.index() == 0); - assert(std::get<0>(v)); - } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant; diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp index a1d9122a8c..5c1bf2bbc0 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // @@ -40,4 +39,5 @@ int main(int, char**) static_assert(!std::is_assignable, std::unique_ptr >::value, ""); static_assert(!std::is_assignable, decltype(nullptr)>::value, ""); + return 0; } diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.fail.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.fail.cpp index 8b883fd2e3..fe4961b4c1 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.fail.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.fail.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp index 820d81e71e..46ccd44096 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,19 +6,16 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// The following compilers don't generate constexpr special members correctly. -// XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8 -// XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0 - -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // // template class variant; -// variant& operator=(variant const&); // constexpr in C++20 +// constexpr variant& operator=(variant const&); #include #include @@ -234,7 +230,6 @@ void test_copy_assignment_sfinae() { } // Make sure we properly propagate triviality (see P0602R4). -#if TEST_STD_VER > 17 { using V = std::variant; static_assert(std::is_trivially_copy_assignable::value, ""); @@ -256,7 +251,6 @@ void test_copy_assignment_sfinae() { using V = std::variant; static_assert(std::is_trivially_copy_assignable::value, ""); } -#endif // > C++17 } void test_copy_assignment_empty_empty() { @@ -380,7 +374,6 @@ void test_copy_assignment_same_index() { #endif // TEST_HAS_NO_EXCEPTIONS // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -437,7 +430,6 @@ void test_copy_assignment_same_index() { static_assert(result.index == 1, ""); static_assert(result.value == 42, ""); } -#endif // > C++17 } void test_copy_assignment_different_index() { @@ -453,7 +445,7 @@ void test_copy_assignment_different_index() { { using V = std::variant; CopyAssign::reset(); - V v1(std::in_place_type, 43); + V v1(std::in_place_type, 43u); V v2(std::in_place_type, 42); assert(CopyAssign::copy_construct == 0); assert(CopyAssign::move_construct == 0); @@ -528,7 +520,6 @@ void test_copy_assignment_different_index() { #endif // TEST_HAS_NO_EXCEPTIONS // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -547,7 +538,7 @@ void test_copy_assignment_different_index() { struct { constexpr Result operator()() const { using V = std::variant; - V v(std::in_place_type, 43); + V v(std::in_place_type, 43u); V v2(std::in_place_type, 42); v = v2; return {v.index(), std::get<1>(v).value}; @@ -557,7 +548,6 @@ void test_copy_assignment_different_index() { static_assert(result.index == 1, ""); static_assert(result.value == 42, ""); } -#endif // > C++17 } template @@ -573,7 +563,6 @@ constexpr bool test_constexpr_assign_imp( void test_constexpr_copy_assignment() { // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 using V = std::variant; static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_copy_assignable::value, ""); @@ -581,7 +570,6 @@ void test_constexpr_copy_assignment() { static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), ""); static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), ""); static_assert(test_constexpr_assign_imp<2>(V(42l), 101), ""); -#endif // > C++17 } int main(int, char**) { diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp index 7ec76ab4cc..775330f8bf 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,20 +6,16 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// The following compilers don't generate constexpr special members correctly. -// XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8 -// XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0 - -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// UNSUPPORTED: c++03, c++11, c++14 +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // // template class variant; -// variant& operator=(variant&&) noexcept(see below); // constexpr in C++20 +// constexpr variant& operator=(variant&&) noexcept(see below); #include #include @@ -200,7 +195,6 @@ void test_move_assignment_sfinae() { } // Make sure we properly propagate triviality (see P0602R4). -#if TEST_STD_VER > 17 { using V = std::variant; static_assert(std::is_trivially_move_assignable::value, ""); @@ -226,7 +220,6 @@ void test_move_assignment_sfinae() { using V = std::variant; static_assert(std::is_trivially_move_assignable::value, ""); } -#endif // > C++17 } void test_move_assignment_empty_empty() { @@ -349,7 +342,6 @@ void test_move_assignment_same_index() { #endif // TEST_HAS_NO_EXCEPTIONS // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -392,7 +384,6 @@ void test_move_assignment_same_index() { static_assert(result.index == 1, ""); static_assert(result.value == 42, ""); } -#endif // > C++17 } void test_move_assignment_different_index() { @@ -407,7 +398,7 @@ void test_move_assignment_different_index() { } { using V = std::variant; - V v1(std::in_place_type, 43); + V v1(std::in_place_type, 43u); V v2(std::in_place_type, 42); MoveAssign::reset(); V &vref = (v1 = std::move(v2)); @@ -443,7 +434,6 @@ void test_move_assignment_different_index() { #endif // TEST_HAS_NO_EXCEPTIONS // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -462,7 +452,7 @@ void test_move_assignment_different_index() { struct { constexpr Result operator()() const { using V = std::variant; - V v(std::in_place_type, 43); + V v(std::in_place_type, 43u); V v2(std::in_place_type, 42); v = std::move(v2); return {v.index(), std::get<1>(v).value}; @@ -472,7 +462,6 @@ void test_move_assignment_different_index() { static_assert(result.index == 1, ""); static_assert(result.value == 42, ""); } -#endif // > C++17 } template @@ -489,7 +478,6 @@ constexpr bool test_constexpr_assign_imp( void test_constexpr_move_assignment() { // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 using V = std::variant; static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_assignable::value, ""); @@ -497,7 +485,6 @@ void test_constexpr_move_assignment() { static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), ""); static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), ""); static_assert(test_constexpr_assign_imp<2>(V(42l), 101), ""); -#endif // > C++17 } int main(int, char**) { diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp index 0824761b09..015c64c7cc 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,8 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// UNSUPPORTED: c++03, c++11, c++14 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp index c0b1560a8f..152f694ce3 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // @@ -38,5 +37,6 @@ int main(int, char**) static_assert(!std::is_constructible, std::true_type>::value, ""); static_assert(!std::is_constructible, std::unique_ptr >::value, ""); static_assert(!std::is_constructible, decltype(nullptr)>::value, ""); - + + return 0; } diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp index 4cd210d3dd..b328ba4cbe 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,15 +6,16 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // // template class variant; -// variant(variant const&); // constexpr in C++20 +// constexpr variant(variant const&); #include #include @@ -120,7 +120,6 @@ void test_copy_ctor_sfinae() { } // Make sure we properly propagate triviality (see P0602R4). -#if TEST_STD_VER > 17 { using V = std::variant; static_assert(std::is_trivially_copy_constructible::value, ""); @@ -138,7 +137,6 @@ void test_copy_ctor_sfinae() { using V = std::variant; static_assert(std::is_trivially_copy_constructible::value, ""); } -#endif // > C++17 } void test_copy_ctor_basic() { @@ -170,7 +168,6 @@ void test_copy_ctor_basic() { } // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 { constexpr std::variant v(std::in_place_index<0>, 42); static_assert(v.index() == 0, ""); @@ -213,7 +210,6 @@ void test_copy_ctor_basic() { static_assert(v2.index() == 1, ""); static_assert(std::get<1>(v2).value == 42, ""); } -#endif // > C++17 } void test_copy_ctor_valueless_by_exception() { @@ -237,21 +233,19 @@ constexpr bool test_constexpr_copy_ctor_imp(std::variant void test_constexpr_copy_ctor() { // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 using V = std::variant; -#ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE +#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible::value, ""); static_assert(std::is_trivially_copy_constructible::value, ""); static_assert(std::is_trivially_move_constructible::value, ""); static_assert(!std::is_copy_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); -#else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE +#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable::value, ""); -#endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE +#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(test_constexpr_copy_ctor_imp<0>(V(42l)), ""); static_assert(test_constexpr_copy_ctor_imp<1>(V(nullptr)), ""); static_assert(test_constexpr_copy_ctor_imp<2>(V(101)), ""); -#endif // > C++17 } int main(int, char**) { @@ -259,15 +253,5 @@ int main(int, char**) { test_copy_ctor_valueless_by_exception(); test_copy_ctor_sfinae(); test_constexpr_copy_ctor(); -#if 0 -// disable this for the moment; it fails on older compilers. -// Need to figure out which compilers will support it. -{ // This is the motivating example from P0739R0 - std::variant v1(3); - std::variant v2 = v1; - (void) v2; -} -#endif - return 0; } diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp index a26abf57cc..17b7242a4d 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_args.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_args.pass.cpp index f404c0ba72..4e96e5989d 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_args.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_args.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_args.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_args.pass.cpp index d46c1d7527..25eed24d59 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_args.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_args.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,11 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// UNSUPPORTED: c++03, c++11, c++14 -// FIXME: Known failure with GCC 7. -// XFAIL: gcc-7 +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_args.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_args.pass.cpp index 9716d05f67..2635b5cc5e 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_args.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_args.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_args.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_args.pass.cpp index 75baf15143..35715057a4 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_args.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_args.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,8 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// UNSUPPORTED: c++03, c++11, c++14 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp index d06b638e69..1c67f020d1 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,15 +6,16 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // // template class variant; -// variant(variant&&) noexcept(see below); // constexpr in C++20 +// constexpr variant(variant&&) noexcept(see below); #include #include @@ -141,7 +141,6 @@ void test_move_ctor_sfinae() { } // Make sure we properly propagate triviality (see P0602R4). -#if TEST_STD_VER > 17 { using V = std::variant; static_assert(std::is_trivially_move_constructible::value, ""); @@ -159,7 +158,6 @@ void test_move_ctor_sfinae() { using V = std::variant; static_assert(std::is_trivially_move_constructible::value, ""); } -#endif // > C++17 } template @@ -210,7 +208,6 @@ void test_move_ctor_basic() { } // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -283,7 +280,6 @@ void test_move_ctor_basic() { static_assert(result.index == 1, ""); static_assert(result.value.value == 42, ""); } -#endif // > C++17 } void test_move_ctor_valueless_by_exception() { @@ -307,22 +303,20 @@ constexpr bool test_constexpr_ctor_imp(std::variant cons void test_constexpr_move_ctor() { // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). -#if TEST_STD_VER > 17 using V = std::variant; -#ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE +#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible::value, ""); static_assert(std::is_trivially_copy_constructible::value, ""); static_assert(std::is_trivially_move_constructible::value, ""); static_assert(!std::is_copy_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); -#else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE +#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable::value, ""); -#endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE +#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_move_constructible::value, ""); static_assert(test_constexpr_ctor_imp<0>(V(42l)), ""); static_assert(test_constexpr_ctor_imp<1>(V(nullptr)), ""); static_assert(test_constexpr_ctor_imp<2>(V(101)), ""); -#endif // > C++17 } int main(int, char**) { diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp index b26ab0c29b..2e026038c9 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp index 07a70e4e8e..37a18496be 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // @@ -111,7 +111,7 @@ void test_basic() { assert(std::get<2>(v) == &x); assert(&ref2 == &std::get<2>(v)); // emplace with multiple args - auto& ref3 = v.emplace<4>(3, 'a'); + auto& ref3 = v.emplace<4>(3u, 'a'); static_assert(std::is_same_v, ""); assert(std::get<4>(v) == "aaa"); assert(&ref3 == &std::get<4>(v)); @@ -145,7 +145,7 @@ void test_basic() { assert(&std::get<3>(v) == &z); assert(&ref4 == &std::get<3>(v)); // emplace with multiple args - auto& ref5 = v.emplace<5>(3, 'a'); + auto& ref5 = v.emplace<5>(3u, 'a'); static_assert(std::is_same_v, ""); assert(std::get<5>(v) == "aaa"); assert(&ref5 == &std::get<5>(v)); diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp index 2660451032..308067897f 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp index 9eaddcc672..eae070e19f 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // @@ -111,7 +111,7 @@ void test_basic() { assert(std::get<2>(v) == &x); assert(&ref2 == &std::get<2>(v)); // emplace with multiple args - auto& ref3 = v.emplace(3, 'a'); + auto& ref3 = v.emplace(3u, 'a'); static_assert(std::is_same_v, ""); assert(std::get<4>(v) == "aaa"); assert(&ref3 == &std::get<4>(v)); @@ -145,7 +145,7 @@ void test_basic() { assert(&std::get(v) == &z); assert(&ref4 == &std::get(v)); // emplace with multiple args - auto& ref5 = v.emplace(3, 'a'); + auto& ref5 = v.emplace(3u, 'a'); static_assert(std::is_same_v, ""); assert(std::get(v) == "aaa"); assert(&ref5 == &std::get(v)); diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp index 5910e50aef..af30e7351b 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.status/index.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.status/index.pass.cpp index 657f9a1ee8..db64f985d0 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.status/index.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.status/index.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp index 2cf1824173..161c5fe0a0 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp index c4cf9f4ba0..b61f508b12 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // @@ -392,7 +392,7 @@ void test_swap_different_alternatives() { assert(std::get<1>(v2).value == 100); } // FIXME: The tests below are just very libc++ specific -#ifdef _LIBCUDACXX_VERSION +#ifdef _LIBCPP_VERSION { using T1 = ThrowsOnSecondMove; using T2 = NonThrowingNonNoexceptType; @@ -426,7 +426,7 @@ void test_swap_different_alternatives() { // testing libc++ extension. If either variant stores a nothrow move // constructible type v1.swap(v2) provides the strong exception safety // guarantee. -#ifdef _LIBCUDACXX_VERSION +#ifdef _LIBCPP_VERSION { using T1 = ThrowingTypeWithNothrowSwap; @@ -466,7 +466,7 @@ void test_swap_different_alternatives() { assert(std::get<0>(v1).value == 42); assert(std::get<1>(v2).value == 100); } -#endif // _LIBCUDACXX_VERSION +#endif // _LIBCPP_VERSION #endif } @@ -578,7 +578,7 @@ void test_swap_noexcept() { } } -#ifdef _LIBCUDACXX_VERSION +#ifdef _LIBCPP_VERSION // This is why variant should SFINAE member swap. :-) template class std::variant; #endif diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_array.fail.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_array.fail.cpp index ccca4460bf..5c41b96f21 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_array.fail.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_array.fail.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_empty.fail.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_empty.fail.cpp index 6953fc9c80..dec4102413 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_empty.fail.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_empty.fail.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_reference.fail.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_reference.fail.cpp index 615802aa31..8b80e4d41f 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_reference.fail.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_reference.fail.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_void.fail.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_void.fail.cpp index f0ba474b23..731793e91e 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_void.fail.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.variant/variant_void.fail.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 // diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp new file mode 100644 index 0000000000..4a651f3a12 --- /dev/null +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include + +#include "test_macros.h" + +struct Incomplete; +template struct Holder { T t; }; + +constexpr bool test(bool do_it) +{ + if (do_it) { + std::variant*, int> v = nullptr; + std::visit([](auto){}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); +#if TEST_STD_VER > 17 + std::visit([](auto){}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); +#endif + } + return true; +} + +int main(int, char**) +{ + test(true); +#if TEST_STD_VER > 17 + static_assert(test(true)); +#endif + return 0; +} diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 5a57164a2b..1e29073bba 100644 --- a/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,10 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions // // template @@ -23,67 +23,8 @@ #include #include "test_macros.h" -#include "type_id.h" #include "variant_test_helpers.h" -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 &&...) & { - set_call(CT_NonConst | CT_LValue); - return true; - } - - template bool operator()(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 &&...) && { - set_call(CT_NonConst | CT_RValue); - return true; - } - - template bool operator()(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 const TypeID *last_call_args; -}; - -CallType ForwardingCallObject::last_call_type = CT_None; -const TypeID *ForwardingCallObject::last_call_args = nullptr; - void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; @@ -136,6 +77,30 @@ void test_call_operator_forwarding() { std::visit(std::move(cobj), v, v2); assert((Fn::check_call(CT_Const | CT_RValue))); } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } } void test_argument_forwarding() { @@ -184,36 +149,86 @@ void test_argument_forwarding() { std::visit(obj, std::move(cv)); assert(Fn::check_call(Val)); } +#endif { // multi argument - multi variant - using S = const std::string &; - using V = std::variant; - const std::string str = "hello"; - long l = 43; - V v1(42); - const V &cv1 = v1; - V v2(str); - const V &cv2 = v2; - V v3(std::move(l)); - const V &cv3 = v3; + using V = std::variant; + V v1(42), v2("hello"), v3(43l); std::visit(obj, v1, v2, v3); - assert((Fn::check_call(Val))); - std::visit(obj, cv1, cv2, std::move(v3)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); + assert((Fn::check_call(Val))); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); } -#endif } -struct ReturnFirst { - template constexpr int operator()(int f, Args &&...) const { - return f; +void test_return_type() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn &cobj = obj; + { // test call operator forwarding - no variant + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } -}; - -struct ReturnArity { - template constexpr int operator()(Args &&...) const { - return sizeof...(Args); + { // test call operator forwarding - single variant, single arg + using V = std::variant; + V v(42); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } -}; + { // test call operator forwarding - single variant, multi arg + using V = std::variant; + V v(42l); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + { // test call operator forwarding - multi variant, multi arg + using V = std::variant; + using V2 = std::variant; + V v(42l); + V2 v2("hello"); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } +} void test_constexpr() { constexpr ReturnFirst obj{}; @@ -246,6 +261,16 @@ void test_constexpr() { constexpr V3 v3; static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + { + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); + } + { + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); + } } void test_exceptions() { @@ -291,10 +316,25 @@ void test_exceptions() { makeEmpty(v2); assert(test(v, v2)); } + { + using V = std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + assert(test(v1, v2, v3, v4)); + } + { + using V = std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + makeEmpty(v2); + makeEmpty(v3); + makeEmpty(v4); + assert(test(v1, v2, v3, v4)); + } #endif } -// See https://bugs.llvm.org/show_bug.cgi?id=31916 +// See https://llvm.org/PR31916 void test_caller_accepts_nonconst() { struct A {}; struct Visitor { @@ -304,12 +344,95 @@ void test_caller_accepts_nonconst() { std::visit(Visitor{}, v); } +struct MyVariant : std::variant {}; + +namespace std { +template +void get(const MyVariant&) { + assert(false); +} +} // namespace std + +void test_derived_from_variant() { + auto v1 = MyVariant{42}; + const auto cv1 = MyVariant{142}; + std::visit([](auto x) { assert(x == 42); }, v1); + std::visit([](auto x) { assert(x == 142); }, cv1); + std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f}); + std::visit([](auto x) { assert(x == 42); }, std::move(v1)); + std::visit([](auto x) { assert(x == 142); }, std::move(cv1)); + + // Check that visit does not take index nor valueless_by_exception members from the base class. + struct EvilVariantBase { + int index; + char valueless_by_exception; + }; + + struct EvilVariant1 : std::variant, + std::tuple, + EvilVariantBase { + using std::variant::variant; + }; + + std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); + + // Check that visit unambiguously picks the variant, even if the other base has __impl member. + struct ImplVariantBase { + struct Callable { + bool operator()() const { assert(false); return false; } + }; + + Callable __impl; + }; + + struct EvilVariant2 : std::variant, ImplVariantBase { + using std::variant::variant; + }; + + std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3}); +} + +struct any_visitor { + template + void operator()(const T&) const {} +}; + +template (), std::declval()))> +constexpr bool has_visit(int) { + return true; +} + +template +constexpr bool has_visit(...) { + return false; +} + +void test_sfinae() { + struct BadVariant : std::variant, std::variant {}; + struct BadVariant2 : private std::variant {}; + struct GoodVariant : std::variant {}; + struct GoodVariant2 : GoodVariant {}; + + static_assert(!has_visit(0)); + static_assert(!has_visit(0)); + static_assert(!has_visit(0)); + static_assert(has_visit>(0)); + static_assert(has_visit(0)); + static_assert(has_visit(0)); +} + int main(int, char**) { test_call_operator_forwarding(); test_argument_forwarding(); + test_return_type(); test_constexpr(); test_exceptions(); test_caller_accepts_nonconst(); + test_derived_from_variant(); + test_sfinae(); return 0; } diff --git a/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp new file mode 100644 index 0000000000..3ae53727df --- /dev/null +++ b/libcudacxx/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -0,0 +1,521 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +template +void test_call_operator_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn &cobj = obj; + { // test call operator forwarding - no variant + std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + std::visit(std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); + } + { // 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))); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } +} + +template +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); + const V &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); + const V &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)); + const V &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)); + } +#endif + { // multi argument - multi variant + using V = std::variant; + V v1(42), v2("hello"), v3(43l); + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); + assert((Fn::check_call(Val))); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); + } +} + +template +void test_return_type() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn &cobj = obj; + { // test call operator forwarding - no variant + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); + } + { // test call operator forwarding - single variant, single arg + using V = std::variant; + V v(42); + static_assert(std::is_same_v(obj, v)), ReturnType>); + static_assert(std::is_same_v(cobj, v)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); + } + { // test call operator forwarding - single variant, multi arg + using V = std::variant; + V v(42l); + static_assert(std::is_same_v(obj, v)), ReturnType>); + static_assert(std::is_same_v(cobj, v)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); + } + { // test call operator forwarding - multi variant, multi arg + using V = std::variant; + using V2 = std::variant; + V v(42l); + V2 v2("hello"); + static_assert(std::is_same_v(obj, v, v2)), ReturnType>); + static_assert(std::is_same_v(cobj, v, v2)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v, v2)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v, v2)), ReturnType>); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); + } + { + using V = std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); + } +} + +void test_constexpr_void() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + { + using V = std::variant; + constexpr V v(42); + static_assert((std::visit(obj, v), 42) == 42, ""); + } + { + using V = std::variant; + constexpr V v(42l); + static_assert((std::visit(obj, v), 42) == 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) == 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) == 3, ""); + } + { + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); + } + { + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); + } +} + +void test_constexpr_int() { + 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, ""); + } + { + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); + } + { + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); + } +} + +template +void test_exceptions() { +#ifndef TEST_HAS_NO_EXCEPTIONS + ReturnArity obj{}; + auto test = [&](auto &&... args) { + try { + std::visit(obj, args...); + } catch (const std::bad_variant_access &) { + 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)); + } + { + using V = std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + assert(test(v1, v2, v3, v4)); + } + { + using V = std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + makeEmpty(v2); + makeEmpty(v3); + makeEmpty(v4); + assert(test(v1, v2, v3, v4)); + } +#endif +} + +// See https://bugs.llvm.org/show_bug.cgi?id=31916 +template +void test_caller_accepts_nonconst() { + struct A {}; + struct Visitor { + auto operator()(A&) { + if constexpr (!std::is_void_v) + { + return ReturnType{}; + } + } + }; + std::variant v; + std::visit(Visitor{}, v); +} + +void test_constexpr_explicit_side_effect() { + auto test_lambda = [](int arg) constexpr { + std::variant v = 101; + std::visit([arg](int& x) constexpr { x = arg; }, v); + return std::get(v); + }; + + static_assert(test_lambda(202) == 202, ""); +} + +void test_derived_from_variant() { + struct MyVariant : std::variant {}; + + std::visit( + [](auto x) { + assert(x == 42); + return true; + }, + MyVariant{42}); + std::visit( + [](auto x) { + assert(x == -1.3f); + return true; + }, + MyVariant{-1.3f}); + + // Check that visit does not take index nor valueless_by_exception members from the base class. + struct EvilVariantBase { + int index; + char valueless_by_exception; + }; + + struct EvilVariant1 : std::variant, + std::tuple, + EvilVariantBase { + using std::variant::variant; + }; + + std::visit( + [](auto x) { + assert(x == 12); + return true; + }, + EvilVariant1{12}); + std::visit( + [](auto x) { + assert(x == 12.3); + return true; + }, + EvilVariant1{12.3}); + + // Check that visit unambiguously picks the variant, even if the other base has __impl member. + struct ImplVariantBase { + struct Callable { + bool operator()() const { assert(false); return false; } + }; + + Callable __impl; + }; + + struct EvilVariant2 : std::variant, ImplVariantBase { + using std::variant::variant; + }; + + std::visit( + [](auto x) { + assert(x == 12); + return true; + }, + EvilVariant2{12}); + std::visit( + [](auto x) { + assert(x == 12.3); + return true; + }, + EvilVariant2{12.3}); +} + +struct any_visitor { + template + bool operator()(const T&) { + return true; + } +}; + +template ( + std::declval(), std::declval()))> +constexpr bool has_visit(int) { + return true; +} + +template +constexpr bool has_visit(...) { + return false; +} + +void test_sfinae() { + struct BadVariant : std::variant, std::variant {}; + + static_assert(has_visit >(int())); + static_assert(!has_visit(int())); +} + +int main(int, char**) { + test_call_operator_forwarding(); + test_argument_forwarding(); + test_return_type(); + test_constexpr_void(); + test_exceptions(); + test_caller_accepts_nonconst(); + test_call_operator_forwarding(); + test_argument_forwarding(); + test_return_type(); + test_constexpr_int(); + test_exceptions(); + test_caller_accepts_nonconst(); + test_constexpr_explicit_side_effect(); + test_derived_from_variant(); + test_sfinae(); + + return 0; +} diff --git a/libcudacxx/libcxx/test/support/variant_test_helpers.h b/libcudacxx/libcxx/test/support/variant_test_helpers.h index 18569601d1..78b3978dde 100644 --- a/libcudacxx/libcxx/test/support/variant_test_helpers.h +++ b/libcudacxx/libcxx/test/support/variant_test_helpers.h @@ -6,6 +6,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + #ifndef SUPPORT_VARIANT_TEST_HELPERS_H #define SUPPORT_VARIANT_TEST_HELPERS_H @@ -14,6 +15,7 @@ #include #include "test_macros.h" +#include "type_id.h" #if TEST_STD_VER <= 14 #error This file requires C++17 @@ -21,7 +23,7 @@ // FIXME: Currently the variant tests are disabled using this macro. #define TEST_VARIANT_HAS_NO_REFERENCES -#ifdef _LIBCUDACXX_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT +#ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT # define TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS #endif @@ -85,5 +87,83 @@ void makeEmpty(Variant& v) { } #endif // TEST_HAS_NO_EXCEPTIONS +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 + ForwardingCallObject& operator()(Args&&...) & { + set_call(CT_NonConst | CT_LValue); + return *this; + } + + template + const ForwardingCallObject& operator()(Args&&...) const & { + set_call(CT_Const | CT_LValue); + return *this; + } + + template + ForwardingCallObject&& operator()(Args&&...) && { + set_call(CT_NonConst | CT_RValue); + return std::move(*this); + } + + template + const ForwardingCallObject&& operator()(Args&&...) const && { + set_call(CT_Const | CT_RValue); + return std::move(*this); + } + + 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; + } + + // To check explicit return type for visit + constexpr operator int() const + { + return 0; + } + + static CallType last_call_type; + static const TypeID *last_call_args; +}; + +CallType ForwardingCallObject::last_call_type = CT_None; +const TypeID *ForwardingCallObject::last_call_args = nullptr; + +struct ReturnFirst { + template constexpr int operator()(int f, Args &&...) const { + return f; + } +}; + +struct ReturnArity { + template constexpr int operator()(Args &&...) const { + return sizeof...(Args); + } +}; #endif // SUPPORT_VARIANT_TEST_HELPERS_H diff --git a/libcudacxx/test/libcudacxx/heterogeneous/variant.pass.cpp b/libcudacxx/test/libcudacxx/heterogeneous/variant.pass.cpp new file mode 100644 index 0000000000..dc36ca0bfc --- /dev/null +++ b/libcudacxx/test/libcudacxx/heterogeneous/variant.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the libcu++ Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++11 +// UNSUPPORTED: msvc-19.16 +// UNSUPPORTED: nvrtc + +// uncomment for a really verbose output detailing what test steps are being launched +// #define DEBUG_TESTERS + +#include "helpers.h" + +#include +#include + +struct pod { + int val; + + __host__ __device__ + friend bool operator==(pod lhs, pod rhs) + { + return lhs.val == rhs.val; + } +}; + +using variant_t = cuda::std::variant; + +template +struct tester +{ + template + __host__ __device__ + static void initialize(Variant && v) + { + v = T{Val}; + } + + template + __host__ __device__ + static void validate(Variant && v) + { + assert(cuda::std::holds_alternative(v)); + assert(cuda::std::get(v) == T{Val}); + } +}; + +using testers = tester_list< + tester, + tester, + tester, + tester, + tester, + tester +>; + +void kernel_invoker() +{ + variant_t v; + validate_not_movable(v); +} + +int main(int arg, char ** argv) +{ +#ifndef __CUDA_ARCH__ + kernel_invoker(); +#endif + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp new file mode 100644 index 0000000000..718823ba94 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.bad_variant_access/bad_variant_access.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 +// UNSUPPORTED: true + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} + +// + +/* + + class bad_variant_access : public exception { +public: + bad_variant_access() noexcept; + virtual const char* what() const noexcept; +}; + +*/ + +#include +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + static_assert(cuda::std::is_base_of::value, + ""); + static_assert(noexcept(cuda::std::bad_variant_access{}), "must be noexcept"); + static_assert(noexcept(cuda::std::bad_variant_access{}.what()), "must be noexcept"); + cuda::std::bad_variant_access ex; + assert(ex.what()); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.general/nothing_to_do.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.general/nothing_to_do.pass.cpp new file mode 100644 index 0000000000..796f3c353b --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.general/nothing_to_do.pass.cpp @@ -0,0 +1,11 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +int main(int, char**) { + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_if_index.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_if_index.pass.cpp new file mode 100644 index 0000000000..48fee56807 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_if_index.pass.cpp @@ -0,0 +1,140 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template +// constexpr add_pointer_t>> +// get_if(variant* v) noexcept; +// template +// constexpr add_pointer_t>> +// get_if(const variant* v) noexcept; + +#include +//#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +__host__ __device__ +void test_const_get_if() { + { + using V = cuda::std::variant; + constexpr const V *v = nullptr; + static_assert(cuda::std::get_if<0>(v) == nullptr, ""); + } + { + using V = cuda::std::variant; + constexpr V v(42); + ASSERT_NOEXCEPT(cuda::std::get_if<0>(&v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), const int *); +#if TEST_STD_VER > 14 && defined(_LIBCUDACXX_ADDRESSOF) + static_assert(*cuda::std::get_if<0>(&v) == 42, ""); +#endif + static_assert(cuda::std::get_if<1>(&v) == nullptr, ""); + } + { + using V = cuda::std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<1>(&v)), const long *); +#if TEST_STD_VER > 14 && defined(_LIBCUDACXX_ADDRESSOF) + static_assert(*cuda::std::get_if<1>(&v) == 42, ""); +#endif + static_assert(cuda::std::get_if<0>(&v) == nullptr, ""); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), int *); + assert(cuda::std::get_if<0>(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), int *); + assert(cuda::std::get_if<0>(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), const int *); + assert(cuda::std::get_if<0>(&v) == &x); + } +#endif +} + +__host__ __device__ +void test_get_if() { + { + using V = cuda::std::variant; + V *v = nullptr; + assert(cuda::std::get_if<0>(v) == nullptr); + } + { + using V = cuda::std::variant; + V v(42); + ASSERT_NOEXCEPT(cuda::std::get_if<0>(&v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), int *); + assert(*cuda::std::get_if<0>(&v) == 42); + assert(cuda::std::get_if<1>(&v) == nullptr); + } + { + using V = cuda::std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<1>(&v)), const long *); + assert(*cuda::std::get_if<1>(&v) == 42); + assert(cuda::std::get_if<0>(&v) == nullptr); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), int *); + assert(cuda::std::get_if<0>(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), const int *); + assert(cuda::std::get_if<0>(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), int *); + assert(cuda::std::get_if<0>(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if<0>(&v)), const int *); + assert(cuda::std::get_if<0>(&v) == &x); + } +#endif +} + +int main(int, char**) { + test_const_get_if(); + test_get_if(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_if_type.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_if_type.pass.cpp new file mode 100644 index 0000000000..7d5ce87c74 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_if_type.pass.cpp @@ -0,0 +1,138 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// 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.h" + +__host__ __device__ +void test_const_get_if() { + { + using V = cuda::std::variant; + constexpr const V *v = nullptr; + static_assert(cuda::std::get_if(v) == nullptr, ""); + } + { + using V = cuda::std::variant; + constexpr V v(42); + ASSERT_NOEXCEPT(cuda::std::get_if(&v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), const int *); +#if TEST_STD_VER > 14 && defined(_LIBCUDACXX_ADDRESSOF) + static_assert(*cuda::std::get_if(&v) == 42, ""); +#endif + static_assert(cuda::std::get_if(&v) == nullptr, ""); + } + { + using V = cuda::std::variant; + constexpr V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), const long *); +#if TEST_STD_VER > 14 && defined(_LIBCUDACXX_ADDRESSOF) + static_assert(*cuda::std::get_if(&v) == 42, ""); +#endif + static_assert(cuda::std::get_if(&v) == nullptr, ""); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), int *); + assert(cuda::std::get_if(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), int *); + assert(cuda::std::get_if(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), const int *); + assert(cuda::std::get_if(&v) == &x); + } +#endif +} + +__host__ __device__ +void test_get_if() { + { + using V = cuda::std::variant; + V *v = nullptr; + assert(cuda::std::get_if(v) == nullptr); + } + { + using V = cuda::std::variant; + V v(42); + ASSERT_NOEXCEPT(cuda::std::get_if(&v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), int *); + assert(*cuda::std::get_if(&v) == 42); + assert(cuda::std::get_if(&v) == nullptr); + } + { + using V = cuda::std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), const long *); + assert(*cuda::std::get_if(&v) == 42); + assert(cuda::std::get_if(&v) == nullptr); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), int *); + assert(cuda::std::get_if(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), const int *); + assert(cuda::std::get_if(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), int *); + assert(cuda::std::get_if(&v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get_if(&v)), const int *); + assert(cuda::std::get_if(&v) == &x); + } +#endif +} + +int main(int, char**) { + test_const_get_if(); + test_get_if(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_index.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_index.pass.cpp new file mode 100644 index 0000000000..1190a6cd90 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_index.pass.cpp @@ -0,0 +1,306 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// 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 +#include + +#include "test_macros.h" +#include "test_workarounds.h" +#include "variant_test_helpers.h" + +__host__ __device__ void test_const_lvalue_get() { + { + using V = cuda::std::variant; + constexpr V v(42); +#if !defined(TEST_COMPILER_MSVC) && \ + !(defined(TEST_COMPILER_GCC) && __GNUC__ < 9) && \ + !defined(TEST_COMPILER_CUDACC_BELOW_11_3) + ASSERT_NOT_NOEXCEPT(cuda::std::get<0>(v)); +#endif // !TEST_COMPILER_MSVC && !(TEST_COMPILER_GCC) && TEST_COMPILER_CUDACC_BELOW_11_3) + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), const int&); + static_assert(cuda::std::get<0>(v) == 42, ""); + } + { + using V = cuda::std::variant; + const V v(42); + ASSERT_NOT_NOEXCEPT(cuda::std::get<0>(v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), const int&); + assert(cuda::std::get<0>(v) == 42); + } + { + using V = cuda::std::variant; + constexpr V v(42l); +#if !defined(TEST_COMPILER_MSVC) && \ + !(defined(TEST_COMPILER_GCC) && __GNUC__ < 9) && \ + !defined(TEST_COMPILER_CUDACC_BELOW_11_3) + ASSERT_NOT_NOEXCEPT(cuda::std::get<1>(v)); +#endif // !TEST_COMPILER_MSVC && !(TEST_COMPILER_GCC && TEST_COMPILER_CUDACC_BELOW_11_3) + ASSERT_SAME_TYPE(decltype(cuda::std::get<1>(v)), const long&); + static_assert(cuda::std::get<1>(v) == 42, ""); + } + { + using V = cuda::std::variant; + const V v(42l); + ASSERT_NOT_NOEXCEPT(cuda::std::get<1>(v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<1>(v)), const long&); + assert(cuda::std::get<1>(v) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), int&); + assert(&cuda::std::get<0>(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), int&); + assert(&cuda::std::get<0>(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), const int&); + assert(&cuda::std::get<0>(v) == &x); + } +#endif +} + +__host__ __device__ void test_lvalue_get() { + { + using V = cuda::std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(cuda::std::get<0>(v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), int&); + assert(cuda::std::get<0>(v) == 42); + } + { + using V = cuda::std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get<1>(v)), const long&); + assert(cuda::std::get<1>(v) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), int&); + assert(&cuda::std::get<0>(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), const int&); + assert(&cuda::std::get<0>(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), int&); + assert(&cuda::std::get<0>(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(v)), const int&); + assert(&cuda::std::get<0>(v) == &x); + } +#endif +} + +__host__ __device__ void test_rvalue_get() { + { + using V = cuda::std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(cuda::std::get<0>(cuda::std::move(v))); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), int&&); + assert(cuda::std::get<0>(cuda::std::move(v)) == 42); + } + { + using V = cuda::std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get<1>(cuda::std::move(v))), + const long&&); + assert(cuda::std::get<1>(cuda::std::move(v)) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), int&); + assert(&cuda::std::get<0>(cuda::std::move(v)) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), + const int&); + assert(&cuda::std::get<0>(cuda::std::move(v)) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), int&&); + int&& xref = cuda::std::get<0>(cuda::std::move(v)); + assert(&xref == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), + const int&&); + const int&& xref = cuda::std::get<0>(cuda::std::move(v)); + assert(&xref == &x); + } +#endif +} + +__host__ __device__ void test_const_rvalue_get() { + { + using V = cuda::std::variant; + const V v(42); + ASSERT_NOT_NOEXCEPT(cuda::std::get<0>(cuda::std::move(v))); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), + const int&&); + assert(cuda::std::get<0>(cuda::std::move(v)) == 42); + } + { + using V = cuda::std::variant; + const V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get<1>(cuda::std::move(v))), + const long&&); + assert(cuda::std::get<1>(cuda::std::move(v)) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), int&); + assert(&cuda::std::get<0>(cuda::std::move(v)) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), + const int&); + assert(&cuda::std::get<0>(cuda::std::move(v)) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), int&&); + int&& xref = cuda::std::get<0>(cuda::std::move(v)); + assert(&xref == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get<0>(cuda::std::move(v))), + const int&&); + const int&& xref = cuda::std::get<0>(cuda::std::move(v)); + assert(&xref == &x); + } +#endif +} + +template +using Idx = cuda::std::integral_constant; + +__host__ __device__ void test_throws_for_all_value_categories() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = cuda::std::variant; + V v0(42); + const V& cv0 = v0; + assert(v0.index() == 0); + V v1(42l); + const V& cv1 = v1; + assert(v1.index() == 1); + cuda::std::integral_constant zero; + cuda::std::integral_constant one; + auto test = [](auto idx, auto&& v) { + using Idx = decltype(idx); + try { + TEST_IGNORE_NODISCARD cuda::std::get( + cuda::std::forward(v)); + } catch (const cuda::std::bad_variant_access&) { + 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, cuda::std::move(v0))); + assert(test(zero, cuda::std::move(v1))); + } + { // const rvalue test cases + assert(test(one, cuda::std::move(cv0))); + assert(test(zero, cuda::std::move(cv1))); + } +#endif +} + +int main(int, char**) { + test_const_lvalue_get(); + test_lvalue_get(); + test_rvalue_get(); + test_const_rvalue_get(); + test_throws_for_all_value_categories(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_type.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_type.pass.cpp new file mode 100644 index 0000000000..9bbc7abe22 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/get_type.pass.cpp @@ -0,0 +1,304 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// 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 +#include + +#include "test_macros.h" +#include "test_workarounds.h" +#include "variant_test_helpers.h" + +__host__ __device__ void test_const_lvalue_get() { + { + using V = cuda::std::variant; + constexpr V v(42); +#if !defined(TEST_COMPILER_MSVC) && \ + !(defined(TEST_COMPILER_GCC) && __GNUC__ < 9) && \ + !defined(TEST_COMPILER_CUDACC_BELOW_11_3) + ASSERT_NOT_NOEXCEPT(cuda::std::get(v)); +#endif // !TEST_COMPILER_MSVC && !(TEST_COMPILER_GCC && TEST_COMPILER_CUDACC_BELOW_11_3) + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), const int&); + static_assert(cuda::std::get(v) == 42, ""); + } + { + using V = cuda::std::variant; + const V v(42); + ASSERT_NOT_NOEXCEPT(cuda::std::get(v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), const int&); + assert(cuda::std::get(v) == 42); + } + { + using V = cuda::std::variant; + constexpr V v(42l); +#if !defined(TEST_COMPILER_MSVC) && \ + !(defined(TEST_COMPILER_GCC) && __GNUC__ < 9) && \ + !defined(TEST_COMPILER_CUDACC_BELOW_11_3) + ASSERT_NOT_NOEXCEPT(cuda::std::get(v)); +#endif // !TEST_COMPILER_MSVC && !(TEST_COMPILER_GCC && TEST_COMPILER_CUDACC_BELOW_11_3) + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), const long&); + static_assert(cuda::std::get(v) == 42, ""); + } + { + using V = cuda::std::variant; + const V v(42l); + ASSERT_NOT_NOEXCEPT(cuda::std::get(v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), const long&); + assert(cuda::std::get(v) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), int&); + assert(&cuda::std::get(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), int&); + assert(&cuda::std::get(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), const int&); + assert(&cuda::std::get(v) == &x); + } +#endif +} + +__host__ __device__ void test_lvalue_get() { + { + using V = cuda::std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(cuda::std::get(v)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), int&); + assert(cuda::std::get(v) == 42); + } + { + using V = cuda::std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), const long&); + assert(cuda::std::get(v) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), int&); + assert(&cuda::std::get(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), const int&); + assert(&cuda::std::get(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), int&); + assert(&cuda::std::get(v) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(v)), const int&); + assert(&cuda::std::get(v) == &x); + } +#endif +} + +__host__ __device__ void test_rvalue_get() { + { + using V = cuda::std::variant; + V v(42); + ASSERT_NOT_NOEXCEPT(cuda::std::get(cuda::std::move(v))); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), int&&); + assert(cuda::std::get(cuda::std::move(v)) == 42); + } + { + using V = cuda::std::variant; + V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + const long&&); + assert(cuda::std::get(cuda::std::move(v)) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), int&); + assert(&cuda::std::get(cuda::std::move(v)) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + const int&); + assert(&cuda::std::get(cuda::std::move(v)) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + int&&); + int&& xref = cuda::std::get(cuda::std::move(v)); + assert(&xref == &x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + const int&&); + const int&& xref = cuda::std::get(cuda::std::move(v)); + assert(&xref == &x); + } +#endif +} + +__host__ __device__ void test_const_rvalue_get() { + { + using V = cuda::std::variant; + const V v(42); + ASSERT_NOT_NOEXCEPT(cuda::std::get(cuda::std::move(v))); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + const int&&); + assert(cuda::std::get(cuda::std::move(v)) == 42); + } + { + using V = cuda::std::variant; + const V v(42l); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + const long&&); + assert(cuda::std::get(cuda::std::move(v)) == 42); + } +// FIXME: Remove these once reference support is reinstated +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), int&); + assert(&cuda::std::get(cuda::std::move(v)) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(x); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + const int&); + assert(&cuda::std::get(cuda::std::move(v)) == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + int&&); + int&& xref = cuda::std::get(cuda::std::move(v)); + assert(&xref == &x); + } + { + using V = cuda::std::variant; + int x = 42; + const V v(cuda::std::move(x)); + ASSERT_SAME_TYPE(decltype(cuda::std::get(cuda::std::move(v))), + const int&&); + const int&& xref = cuda::std::get(cuda::std::move(v)); + assert(&xref == &x); + } +#endif +} + +template +struct identity { + using type = Tp; +}; + +__host__ __device__ void test_throws_for_all_value_categories() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = cuda::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 { + TEST_IGNORE_NODISCARD cuda::std::get( + cuda::std::forward(v)); + } catch (const cuda::std::bad_variant_access&) { + 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, cuda::std::move(v0))); + assert(test(zero, cuda::std::move(v1))); + } + { // const rvalue test cases + assert(test(one, cuda::std::move(cv0))); + assert(test(zero, cuda::std::move(cv1))); + } +#endif +} + +int main(int, char**) { + test_const_lvalue_get(); + test_lvalue_get(); + test_rvalue_get(); + test_const_rvalue_get(); + test_throws_for_all_value_categories(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/holds_alternative.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/holds_alternative.pass.cpp new file mode 100644 index 0000000000..d2a91e7f8e --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.get/holds_alternative.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template +// constexpr bool holds_alternative(const variant& v) noexcept; + +#include + +#include "test_macros.h" + +int main(int, char**) { + { + using V = cuda::std::variant; + constexpr V v; + static_assert(cuda::std::holds_alternative(v), ""); + } + { + using V = cuda::std::variant; + constexpr V v; + static_assert(cuda::std::holds_alternative(v), ""); + static_assert(!cuda::std::holds_alternative(v), ""); + } + { // noexcept test + using V = cuda::std::variant; + const V v; + ASSERT_NOEXCEPT(cuda::std::holds_alternative(v)); + } + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_alternative.fail.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_alternative.fail.cpp new file mode 100644 index 0000000000..4ad68b8dc9 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_alternative.fail.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// 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 +#include + +int main(int, char**) { + using V = cuda::std::variant; + cuda::std::variant_alternative<4, V>::type foo; // expected-error@variant:* {{Index out of bounds in cuda::std::variant_alternative<>}} + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp new file mode 100644 index 0000000000..98f1d2e11e --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_alternative.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// 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 +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +template __host__ __device__ void test() { + static_assert( + cuda::std::is_same_v::type, E>, ""); + static_assert( + cuda::std::is_same_v::type, + const E>, + ""); + static_assert( + cuda::std::is_same_v::type, + volatile E>, + ""); + static_assert( + cuda::std::is_same_v< + typename cuda::std::variant_alternative::type, + const volatile E>, + ""); + static_assert(cuda::std::is_same_v, E>, ""); + static_assert(cuda::std::is_same_v, const E>, + ""); + static_assert( + cuda::std::is_same_v, volatile E>, + ""); + static_assert(cuda::std::is_same_v, + const volatile E>, + ""); +} + +int main(int, char**) { +#ifndef _LIBCUDACXX_HAS_NO_LONG_DOUBLE + { + using V = cuda::std::variant; + test(); + test(); + test(); + + test(); + } +#endif // _LIBCUDACXX_HAS_NO_LONG_DOUBLE +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + test(); + test(); + test(); + test(); + test(); + } +#endif + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_size.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_size.pass.cpp new file mode 100644 index 0000000000..d4d6bee898 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.helpers/variant_size.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// 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 +#include + +#include "test_macros.h" + +template __host__ __device__ void test() { + static_assert(cuda::std::variant_size::value == E, ""); + static_assert(cuda::std::variant_size::value == E, ""); + static_assert(cuda::std::variant_size::value == E, ""); + static_assert(cuda::std::variant_size::value == E, ""); + static_assert(cuda::std::variant_size_v == E, ""); + static_assert(cuda::std::variant_size_v == E, ""); + static_assert(cuda::std::variant_size_v == E, ""); + static_assert(cuda::std::variant_size_v == E, ""); + static_assert(cuda::std::is_base_of, + cuda::std::variant_size>::value, + ""); +}; + +int main(int, char**) { + test, 0>(); + test, 1>(); + test, 4>(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.monostate.relops/relops.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.monostate.relops/relops.pass.cpp new file mode 100644 index 0000000000..4cecca9da1 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.monostate.relops/relops.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// 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; } +// constexpr strong_ordering operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; } // since C++20 + +#include +#include + +#include "test_comparisons.h" +#include "test_macros.h" + +__host__ __device__ +constexpr bool test() { + using M = cuda::std::monostate; + constexpr M m1{}; + constexpr M m2{}; + assert(testComparisons(m1, m2, /*isEqual*/ true, /*isLess*/ false)); + AssertComparisonsAreNoexcept(); + +#ifndef _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR + assert(testOrder(m1, m2, cuda::std::strong_ordering::equal)); + AssertOrderAreNoexcept(); +#endif // _LIBCUDACXX_HAS_NO_SPACESHIP_OPERATOR + + return true; +} + +int main(int, char**) { + test(); + static_assert(test(), ""); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.monostate/monostate.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.monostate/monostate.pass.cpp new file mode 100644 index 0000000000..4505e7558e --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.monostate/monostate.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// struct monostate {}; + +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + using M = cuda::std::monostate; + static_assert(cuda::std::is_trivially_default_constructible::value, ""); + static_assert(cuda::std::is_trivially_copy_constructible::value, ""); + static_assert(cuda::std::is_trivially_copy_assignable::value, ""); + static_assert(cuda::std::is_trivially_destructible::value, ""); + constexpr M m{}; + ((void)m); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/relops.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/relops.pass.cpp new file mode 100644 index 0000000000..a2659f355b --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/relops.pass.cpp @@ -0,0 +1,290 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// 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 + +#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==(const MakeEmptyT &, const MakeEmptyT &) { + assert(false); + return false; +} +inline bool operator!=(const MakeEmptyT &, const MakeEmptyT &) { + assert(false); + return false; +} +inline bool operator<(const MakeEmptyT &, const MakeEmptyT &) { + assert(false); + return false; +} +inline bool operator<=(const MakeEmptyT &, const MakeEmptyT &) { + assert(false); + return false; +} +inline bool operator>(const MakeEmptyT &, const MakeEmptyT &) { + assert(false); + return false; +} +inline bool operator>=(const MakeEmptyT &, const MakeEmptyT &) { + assert(false); + return false; +} + +template void makeEmpty(Variant &v) { + Variant v2(cuda::std::in_place_type); + try { + v = cuda::std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +struct MyBool { + bool value; + __host__ __device__ + constexpr explicit MyBool(bool v) : value(v) {} + __host__ __device__ + constexpr operator bool() const noexcept { return value; } +}; + +struct ComparesToMyBool { + int value = 0; +}; +__host__ __device__ +inline constexpr MyBool operator==(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { + return MyBool(LHS.value == RHS.value); +} +__host__ __device__ +inline constexpr MyBool operator!=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { + return MyBool(LHS.value != RHS.value); +} +__host__ __device__ +inline constexpr MyBool operator<(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { + return MyBool(LHS.value < RHS.value); +} +__host__ __device__ +inline constexpr MyBool operator<=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { + return MyBool(LHS.value <= RHS.value); +} +__host__ __device__ +inline constexpr MyBool operator>(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { + return MyBool(LHS.value > RHS.value); +} +__host__ __device__ +inline constexpr MyBool operator>=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { + return MyBool(LHS.value >= RHS.value); +} + +template +__host__ __device__ +void test_equality_basic() { + { + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<0>, T1{42}); + constexpr V v2(cuda::std::in_place_index<0>, T1{42}); + static_assert(v1 == v2, ""); + static_assert(v2 == v1, ""); + static_assert(!(v1 != v2), ""); + static_assert(!(v2 != v1), ""); + } + { + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<0>, T1{42}); + constexpr V v2(cuda::std::in_place_index<0>, T1{43}); + static_assert(!(v1 == v2), ""); + static_assert(!(v2 == v1), ""); + static_assert(v1 != v2, ""); + static_assert(v2 != v1, ""); + } + { + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<0>, T1{42}); + constexpr V v2(cuda::std::in_place_index<1>, T2{42}); + static_assert(!(v1 == v2), ""); + static_assert(!(v2 == v1), ""); + static_assert(v1 != v2, ""); + static_assert(v2 != v1, ""); + } + { + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<1>, T2{42}); + constexpr V v2(cuda::std::in_place_index<1>, T2{42}); + static_assert(v1 == v2, ""); + static_assert(v2 == v1, ""); + static_assert(!(v1 != v2), ""); + static_assert(!(v2 != v1), ""); + } +} + +__host__ __device__ +void test_equality() { + test_equality_basic(); + test_equality_basic(); + test_equality_basic(); + test_equality_basic(); +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = cuda::std::variant; + V v1; + V v2; + makeEmpty(v2); + assert(!(v1 == v2)); + assert(!(v2 == v1)); + assert(v1 != v2); + assert(v2 != v1); + } + { + using V = cuda::std::variant; + V v1; + makeEmpty(v1); + V v2; + assert(!(v1 == v2)); + assert(!(v2 == v1)); + assert(v1 != v2); + assert(v2 != v1); + } + { + using V = cuda::std::variant; + V v1; + makeEmpty(v1); + V v2; + makeEmpty(v2); + assert(v1 == v2); + assert(v2 == v1); + assert(!(v1 != v2)); + assert(!(v2 != v1)); + } +#endif +} + +template +__host__ __device__ +constexpr bool test_less(const Var &l, const Var &r, bool expect_less, + bool expect_greater) { + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v r), bool>, ""); + static_assert(cuda::std::is_same_v= r), bool>, ""); + + return ((l < r) == expect_less) && (!(l >= r) == expect_less) && + ((l > r) == expect_greater) && (!(l <= r) == expect_greater); +} + +template +__host__ __device__ +void test_relational_basic() { + { // same index, same value + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<0>, T1{1}); + constexpr V v2(cuda::std::in_place_index<0>, T1{1}); + static_assert(test_less(v1, v2, false, false), ""); + } + { // same index, value < other_value + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<0>, T1{0}); + constexpr V v2(cuda::std::in_place_index<0>, T1{1}); + static_assert(test_less(v1, v2, true, false), ""); + } + { // same index, value > other_value + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<0>, T1{1}); + constexpr V v2(cuda::std::in_place_index<0>, T1{0}); + static_assert(test_less(v1, v2, false, true), ""); + } + { // LHS.index() < RHS.index() + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<0>, T1{0}); + constexpr V v2(cuda::std::in_place_index<1>, T2{0}); + static_assert(test_less(v1, v2, true, false), ""); + } + { // LHS.index() > RHS.index() + using V = cuda::std::variant; + constexpr V v1(cuda::std::in_place_index<1>, T2{0}); + constexpr V v2(cuda::std::in_place_index<0>, T1{0}); + static_assert(test_less(v1, v2, false, true), ""); + } +} + +__host__ __device__ +void test_relational() { + test_relational_basic(); + test_relational_basic(); + test_relational_basic(); + test_relational_basic(); +#ifndef TEST_HAS_NO_EXCEPTIONS + { // LHS.index() < RHS.index(), RHS is empty + using V = cuda::std::variant; + V v1; + V v2; + makeEmpty(v2); + assert(test_less(v1, v2, false, true)); + } + { // LHS.index() > RHS.index(), LHS is empty + using V = cuda::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 = cuda::std::variant; + V v1; + makeEmpty(v1); + V v2; + makeEmpty(v2); + assert(test_less(v1, v2, false, false)); + } +#endif +} + +int main(int, char**) { + test_equality(); + test_relational(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp new file mode 100644 index 0000000000..d7653cf810 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// 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 + +#include "test_macros.h" + + +struct MyBoolExplicit { + bool value; + constexpr explicit MyBoolExplicit(bool v) : value(v) {} + constexpr explicit operator bool() const noexcept { return value; } +}; + +struct ComparesToMyBoolExplicit { + int value = 0; +}; +inline constexpr MyBoolExplicit operator==(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value == RHS.value); +} +inline constexpr MyBoolExplicit operator!=(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value != RHS.value); +} +inline constexpr MyBoolExplicit operator<(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value < RHS.value); +} +inline constexpr MyBoolExplicit operator<=(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value <= RHS.value); +} +inline constexpr MyBoolExplicit operator>(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value > RHS.value); +} +inline constexpr MyBoolExplicit operator>=(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value >= RHS.value); +} + + +int main(int, char**) { + using V = cuda::std::variant; + V v1(42); + V v2(101); + // expected-error-re@variant:* 6 {{{{(static_assert|static assertion)}} failed{{.*}}the relational operator does not return a type which is implicitly convertible to bool}} + // expected-error@variant:* 6 {{no viable conversion}} + (void)(v1 == v2); // expected-note {{here}} + (void)(v1 != v2); // expected-note {{here}} + (void)(v1 < v2); // expected-note {{here}} + (void)(v1 <= v2); // expected-note {{here}} + (void)(v1 > v2); // expected-note {{here}} + (void)(v1 >= v2); // expected-note {{here}} + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/three_way.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/three_way.pass.cpp new file mode 100644 index 0000000000..b399a7741e --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.relops/three_way.pass.cpp @@ -0,0 +1,196 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: msvc-19.16 +// UNSUPPORTED: true + +// + +// template class variant; + +// template requires (three_way_comparable && ...) +// constexpr cuda::std::common_comparison_category_t< +// cuda::std::compare_three_way_result_t...> +// operator<=>(const variant& t, const variant& u); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_comparisons.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +// MakeEmptyT throws in operator=(&&), so we can move to it to create valueless-by-exception variants. +struct MakeEmptyT { + MakeEmptyT() = default; + MakeEmptyT(MakeEmptyT&&) { throw 42; } + MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; } +}; +inline bool operator==(const MakeEmptyT&, const MakeEmptyT&) { + assert(false); + return false; +} +inline cuda::std::weak_ordering operator<=>(const MakeEmptyT&, const MakeEmptyT&) { + assert(false); + return cuda::std::weak_ordering::equivalent; +} + +template +void makeEmpty(Variant& v) { + Variant v2(cuda::std::in_place_type); + try { + v = cuda::std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} + +void test_empty() { + { + using V = cuda::std::variant; + V v1; + V v2; + makeEmpty(v2); + assert(testOrder(v1, v2, cuda::std::weak_ordering::greater)); + } + { + using V = cuda::std::variant; + V v1; + makeEmpty(v1); + V v2; + assert(testOrder(v1, v2, cuda::std::weak_ordering::less)); + } + { + using V = cuda::std::variant; + V v1; + makeEmpty(v1); + V v2; + makeEmpty(v2); + assert(testOrder(v1, v2, cuda::std::weak_ordering::equivalent)); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +template +constexpr bool test_with_types() { + using V = cuda::std::variant; + AssertOrderReturn(); + { // same index, same value + constexpr V v1(cuda::std::in_place_index<0>, T1{1}); + constexpr V v2(cuda::std::in_place_index<0>, T1{1}); + assert(testOrder(v1, v2, Order::equivalent)); + } + { // same index, value < other_value + constexpr V v1(cuda::std::in_place_index<0>, T1{0}); + constexpr V v2(cuda::std::in_place_index<0>, T1{1}); + assert(testOrder(v1, v2, Order::less)); + } + { // same index, value > other_value + constexpr V v1(cuda::std::in_place_index<0>, T1{1}); + constexpr V v2(cuda::std::in_place_index<0>, T1{0}); + assert(testOrder(v1, v2, Order::greater)); + } + { // LHS.index() < RHS.index() + constexpr V v1(cuda::std::in_place_index<0>, T1{0}); + constexpr V v2(cuda::std::in_place_index<1>, T2{0}); + assert(testOrder(v1, v2, Order::less)); + } + { // LHS.index() > RHS.index() + constexpr V v1(cuda::std::in_place_index<1>, T2{0}); + constexpr V v2(cuda::std::in_place_index<0>, T1{0}); + assert(testOrder(v1, v2, Order::greater)); + } + + return true; +} + +constexpr bool test_three_way() { + assert((test_with_types())); + assert((test_with_types())); + + { + using V = cuda::std::variant; + constexpr double nan = cuda::std::numeric_limits::quiet_NaN(); + { + constexpr V v1(cuda::std::in_place_type, 1); + constexpr V v2(cuda::std::in_place_type, nan); + assert(testOrder(v1, v2, cuda::std::partial_ordering::less)); + } + { + constexpr V v1(cuda::std::in_place_type, nan); + constexpr V v2(cuda::std::in_place_type, 2); + assert(testOrder(v1, v2, cuda::std::partial_ordering::greater)); + } + { + constexpr V v1(cuda::std::in_place_type, nan); + constexpr V v2(cuda::std::in_place_type, nan); + assert(testOrder(v1, v2, cuda::std::partial_ordering::unordered)); + } + } + + return true; +} + +// SFINAE tests +template +concept has_three_way_op = requires (T& t, U& u) { t <=> u; }; + +// cuda::std::three_way_comparable is a more stringent requirement that demands +// operator== and a few other things. +using cuda::std::three_way_comparable; + +struct HasSimpleOrdering { + constexpr bool operator==(const HasSimpleOrdering&) const; + constexpr bool operator<(const HasSimpleOrdering&) const; +}; + +struct HasOnlySpaceship { + constexpr bool operator==(const HasOnlySpaceship&) const = delete; + constexpr cuda::std::weak_ordering operator<=>(const HasOnlySpaceship&) const; +}; + +struct HasFullOrdering { + constexpr bool operator==(const HasFullOrdering&) const; + constexpr cuda::std::weak_ordering operator<=>(const HasFullOrdering&) const; +}; + +// operator<=> must resolve the return types of all its union types' +// operator<=>s to determine its own return type, so it is detectable by SFINAE +static_assert(!has_three_way_op); +static_assert(!has_three_way_op>); + +static_assert(!three_way_comparable); +static_assert(!three_way_comparable>); + +static_assert(has_three_way_op); +static_assert(!has_three_way_op>); + +static_assert(!three_way_comparable); +static_assert(!three_way_comparable>); + +static_assert( has_three_way_op); +static_assert( has_three_way_op>); + +static_assert( three_way_comparable); +static_assert( three_way_comparable>); + +int main(int, char**) { + test_three_way(); + static_assert(test_three_way()); + +#ifndef TEST_HAS_NO_EXCEPTIONS + test_empty(); +#endif // TEST_HAS_NO_EXCEPTIONS + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp new file mode 100644 index 0000000000..b4d6bb4e74 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.synopsis/variant_npos.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// constexpr size_t variant_npos = -1; + +#include + +#include "test_macros.h" + +int main(int, char**) { + static_assert(cuda::std::variant_npos == static_cast(-1), ""); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/implicit_ctad.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/implicit_ctad.pass.cpp new file mode 100644 index 0000000000..a7f174db83 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/implicit_ctad.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + +// Make sure that the implicitly-generated CTAD works. + +// We make sure that it is not ill-formed, however we still produce a warning for +// this one because explicit construction from a variant using CTAD is ambiguous +// (in the sense that the programer intent is not clear). +// ADDITIONAL_COMPILE_FLAGS: -Wno-ctad-maybe-unsupported + +#include + +#include "test_macros.h" + +int main(int, char**) { + // This is the motivating example from P0739R0 + { + cuda::std::variant v1(3); + cuda::std::variant v2 = v1; + ASSERT_SAME_TYPE(decltype(v2), cuda::std::variant); + unused(v2); + } + + { + cuda::std::variant v1(3); + cuda::std::variant v2 = cuda::std::variant(v1); // Technically valid, but intent is ambiguous! + ASSERT_SAME_TYPE(decltype(v2), cuda::std::variant); + unused(v2); + } + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp new file mode 100644 index 0000000000..9c6c937af7 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -0,0 +1,340 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template +// variant& operator=(T&&) noexcept(see below); + +#include +// #include +#include +#include +// #include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +namespace MetaHelpers { + +struct Dummy { + Dummy() = default; +}; + +struct ThrowsCtorT { + __host__ __device__ + ThrowsCtorT(int) noexcept(false) {} + __host__ __device__ + ThrowsCtorT &operator=(int) noexcept { return *this; } +}; + +struct ThrowsAssignT { + __host__ __device__ + ThrowsAssignT(int) noexcept {} + __host__ __device__ + ThrowsAssignT &operator=(int) noexcept(false) { return *this; } +}; + +struct NoThrowT { + __host__ __device__ + NoThrowT(int) noexcept {} + __host__ __device__ + NoThrowT &operator=(int) noexcept { return *this; } +}; + +} // namespace MetaHelpers + +namespace RuntimeHelpers { +#ifndef TEST_HAS_NO_EXCEPTIONS + +struct ThrowsCtorT { + int value; + __host__ __device__ + ThrowsCtorT() : value(0) {} + __host__ __device__ + ThrowsCtorT(int) noexcept(false) { throw 42; } + __host__ __device__ + ThrowsCtorT &operator=(int v) noexcept { + value = v; + return *this; + } +}; + +struct MoveCrashes { + int value; + __host__ __device__ + MoveCrashes(int v = 0) noexcept : value{v} {} + __host__ __device__ + MoveCrashes(MoveCrashes &&) noexcept { assert(false); } + __host__ __device__ + MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; } + __host__ __device__ + MoveCrashes &operator=(int v) noexcept { + value = v; + return *this; + } +}; + +struct ThrowsCtorTandMove { + int value; + __host__ __device__ + ThrowsCtorTandMove() : value(0) {} + __host__ __device__ + ThrowsCtorTandMove(int) noexcept(false) { throw 42; } + __host__ __device__ + ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); } + __host__ __device__ + ThrowsCtorTandMove &operator=(int v) noexcept { + value = v; + return *this; + } +}; + +struct ThrowsAssignT { + int value; + __host__ __device__ + ThrowsAssignT() : value(0) {} + __host__ __device__ + ThrowsAssignT(int v) noexcept : value(v) {} + __host__ __device__ + ThrowsAssignT &operator=(int) noexcept(false) { throw 42; } +}; + +struct NoThrowT { + int value; + __host__ __device__ + NoThrowT() : value(0) {} + __host__ __device__ + NoThrowT(int v) noexcept : value(v) {} + __host__ __device__ + NoThrowT &operator=(int v) noexcept { + value = v; + return *this; + } +}; + +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) +} // namespace RuntimeHelpers + +__host__ __device__ +void test_T_assignment_noexcept() { + using namespace MetaHelpers; + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_assignable::value, ""); + } +} + +__host__ __device__ +void test_T_assignment_sfinae() { + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_assignable::value, "ambiguous"); + } + /*{ + using V = cuda::std::variant; + static_assert(!cuda::std::is_assignable::value, "ambiguous"); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_assignable::value, "no matching operator="); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_assignable::value == VariantAllowsNarrowingConversions, + "no matching operator="); + } + { + using V = cuda::std::variant, bool>; + static_assert(!cuda::std::is_assignable>::value, + "no explicit bool in operator="); + struct X { + operator void*(); + }; + static_assert(!cuda::std::is_assignable::value, + "no boolean conversion in operator="); + static_assert(!cuda::std::is_assignable::value, + "no converted to bool in operator="); + }*/ + { + // mdominiak: this was originally not an aggregate and we should probably bring that back + // eventually, except... https://www.godbolt.org/z/oanheq7bv + struct X { X() = default; }; + struct Y { + __host__ __device__ operator X(); + }; + using V = cuda::std::variant; + static_assert(cuda::std::is_assignable::value, + "regression on user-defined conversions in operator="); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_assignable::value, "ambiguous"); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_assignable::value, "ambiguous"); + } +#endif // TEST_VARIANT_HAS_NO_REFERENCES +} + +__host__ __device__ +void test_T_assignment_basic() { + { + cuda::std::variant v(43); + v = 42; + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == 42); + } + { + cuda::std::variant v(43l); + v = 42; + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == 42); + v = 43l; + assert(v.index() == 1); + assert(cuda::std::get<1>(v) == 43); + } +#ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS + { + cuda::std::variant v; + v = 42; + assert(v.index() == 1); + assert(cuda::std::get<1>(v) == 42); + v = 43u; + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == 43); + } +#endif + /*{ + cuda::std::variant v = true; + v = "bar"; + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == "bar"); + } + { + cuda::std::variant> v; + v = nullptr; + assert(v.index() == 1); + assert(cuda::std::get<1>(v) == nullptr); + }*/ +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + int x = 42; + V v(43l); + v = x; + assert(v.index() == 0); + assert(&cuda::std::get<0>(v) == &x); + v = cuda::std::move(x); + assert(v.index() == 1); + assert(&cuda::std::get<1>(v) == &x); + // 'long' is selected by FUN(const int &) since 'const int &' cannot bind + // to 'int&'. + const int &cx = x; + v = cx; + assert(v.index() == 2); + assert(cuda::std::get<2>(v) == 42); + } +#endif // TEST_VARIANT_HAS_NO_REFERENCES +} + +__host__ __device__ +void test_T_assignment_performs_construction() { + using namespace RuntimeHelpers; +#ifndef TEST_HAS_NO_EXCEPTIONS + /*{ + using V = cuda::std::variant; + V v(cuda::std::in_place_type, "hello"); + try { + v = 42; + assert(false); + } catch (...) { / * ... * / + } + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == "hello"); + } + { + using V = cuda::std::variant; + V v(cuda::std::in_place_type, "hello"); + v = 42; + assert(v.index() == 0); + assert(cuda::std::get<0>(v).value == 42); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS +} + +__host__ __device__ +void test_T_assignment_performs_assignment() { + using namespace RuntimeHelpers; +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = cuda::std::variant; + V v; + v = 42; + assert(v.index() == 0); + assert(cuda::std::get<0>(v).value == 42); + } + /*{ + using V = cuda::std::variant; + V v; + v = 42; + assert(v.index() == 0); + assert(cuda::std::get<0>(v).value == 42); + }*/ + { + using V = cuda::std::variant; + V v(100); + try { + v = 42; + assert(false); + } catch (...) { /* ... */ + } + assert(v.index() == 0); + assert(cuda::std::get<0>(v).value == 100); + } + { + using V = cuda::std::variant; + V v(100); + try { + v = 42; + assert(false); + } catch (...) { /* ... */ + } + assert(v.index() == 1); + assert(cuda::std::get<1>(v).value == 100); + } +#endif // TEST_HAS_NO_EXCEPTIONS +} + +int main(int, char**) { + test_T_assignment_basic(); + test_T_assignment_performs_construction(); + test_T_assignment_performs_assignment(); + test_T_assignment_noexcept(); + test_T_assignment_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp new file mode 100644 index 0000000000..3f981022cd --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + +// template +// variant& operator=(T&&) noexcept(see below); + +#include +// #include +// #include + +#include "variant_test_helpers.h" + +int main(int, char**) +{ + static_assert(!cuda::std::is_assignable, int>::value, ""); + static_assert(!cuda::std::is_assignable, int>::value, ""); + static_assert(cuda::std::is_assignable, int>::value == VariantAllowsNarrowingConversions, ""); + + // static_assert(cuda::std::is_assignable, int>::value == VariantAllowsNarrowingConversions, ""); + // static_assert(cuda::std::is_assignable, int>::value == VariantAllowsNarrowingConversions, ""); + // static_assert(!cuda::std::is_assignable, int>::value, ""); + + static_assert(!cuda::std::is_assignable, decltype("meow")>::value, ""); + static_assert(!cuda::std::is_assignable, decltype("meow")>::value, ""); + static_assert(!cuda::std::is_assignable, decltype("meow")>::value, ""); + + static_assert(!cuda::std::is_assignable, cuda::std::true_type>::value, ""); + // static_assert(!cuda::std::is_assignable, cuda::std::unique_ptr >::value, ""); + static_assert(!cuda::std::is_assignable, decltype(nullptr)>::value, ""); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/copy.fail.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/copy.fail.cpp new file mode 100644 index 0000000000..638653b12e --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/copy.fail.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// LWG issue 3024 + +#include +#include + +struct NotCopyConstructible +{ + NotCopyConstructible() = default; + NotCopyConstructible(NotCopyConstructible const&) = delete; +}; + +int main(int, char**) +{ + static_assert(!cuda::std::is_copy_constructible_v); + + cuda::std::variant v; + cuda::std::variant v1; + cuda::std::variant v2(v); // expected-error {{call to implicitly-deleted copy constructor of 'cuda::std::variant'}} + v1 = v; // expected-error-re {{object of type 'std:{{.*}}:variant' cannot be assigned because its copy assignment operator is implicitly deleted}} +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp new file mode 100644 index 0000000000..8f49bc5f7b --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp @@ -0,0 +1,641 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// constexpr variant& operator=(variant const&); + +#include +// #include +#include +#include + +#include "test_macros.h" + +struct NoCopy { + NoCopy(const NoCopy &) = delete; + NoCopy &operator=(const NoCopy &) = default; +}; + +struct CopyOnly { + CopyOnly(const CopyOnly &) = default; + CopyOnly(CopyOnly &&) = delete; + CopyOnly &operator=(const CopyOnly &) = default; + CopyOnly &operator=(CopyOnly &&) = delete; +}; + +struct MoveOnly { + MoveOnly(const MoveOnly &) = delete; + MoveOnly(MoveOnly &&) = default; + MoveOnly &operator=(const MoveOnly &) = default; +}; + +struct MoveOnlyNT { + MoveOnlyNT(const MoveOnlyNT &) = delete; + __host__ __device__ + MoveOnlyNT(MoveOnlyNT &&) {} + MoveOnlyNT &operator=(const MoveOnlyNT &) = default; +}; + +struct CopyAssign { + STATIC_MEMBER_VAR(alive, int); + STATIC_MEMBER_VAR(copy_construct, int); + STATIC_MEMBER_VAR(copy_assign, int); + STATIC_MEMBER_VAR(move_construct, int); + STATIC_MEMBER_VAR(move_assign, int); + __host__ __device__ + static void reset() { + copy_construct() = copy_assign() = move_construct() = move_assign() = alive() = 0; + } + __host__ __device__ + CopyAssign(int v) : value(v) { ++alive(); } + __host__ __device__ + CopyAssign(const CopyAssign &o) : value(o.value) { + ++alive(); + ++copy_construct(); + } + __host__ __device__ + CopyAssign(CopyAssign &&o) noexcept : value(o.value) { + o.value = -1; + ++alive(); + ++move_construct(); + } + __host__ __device__ + CopyAssign &operator=(const CopyAssign &o) { + value = o.value; + ++copy_assign(); + return *this; + } + __host__ __device__ + CopyAssign &operator=(CopyAssign &&o) noexcept { + value = o.value; + o.value = -1; + ++move_assign(); + return *this; + } + __host__ __device__ + ~CopyAssign() { --alive(); } + int value; +}; + +struct CopyMaybeThrows { + __host__ __device__ CopyMaybeThrows(const CopyMaybeThrows &); + __host__ __device__ CopyMaybeThrows &operator=(const CopyMaybeThrows &); +}; +struct CopyDoesThrow { + __host__ __device__ CopyDoesThrow(const CopyDoesThrow &) noexcept(false); + __host__ __device__ CopyDoesThrow &operator=(const CopyDoesThrow &) noexcept(false); +}; + + +struct NTCopyAssign { + __host__ __device__ + constexpr NTCopyAssign(int v) : value(v) {} + NTCopyAssign(const NTCopyAssign &) = default; + NTCopyAssign(NTCopyAssign &&) = default; + __host__ __device__ + NTCopyAssign &operator=(const NTCopyAssign &that) { + value = that.value; + return *this; + }; + NTCopyAssign &operator=(NTCopyAssign &&) = delete; + int value; +}; + +static_assert(!cuda::std::is_trivially_copy_assignable::value, ""); +static_assert(cuda::std::is_copy_assignable::value, ""); + +struct TCopyAssign { + __host__ __device__ + constexpr TCopyAssign(int v) : value(v) {} + TCopyAssign(const TCopyAssign &) = default; + TCopyAssign(TCopyAssign &&) = default; + TCopyAssign &operator=(const TCopyAssign &) = default; + TCopyAssign &operator=(TCopyAssign &&) = delete; + int value; +}; + +static_assert(cuda::std::is_trivially_copy_assignable::value, ""); + +struct TCopyAssignNTMoveAssign { + __host__ __device__ + constexpr TCopyAssignNTMoveAssign(int v) : value(v) {} + TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign &) = default; + TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign &&) = default; + TCopyAssignNTMoveAssign &operator=(const TCopyAssignNTMoveAssign &) = default; + __host__ __device__ + TCopyAssignNTMoveAssign &operator=(TCopyAssignNTMoveAssign &&that) { + value = that.value; + that.value = -1; + return *this; + } + int value; +}; + +static_assert(cuda::std::is_trivially_copy_assignable_v, ""); + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct CopyThrows { + CopyThrows() = default; + __host__ __device__ + CopyThrows(const CopyThrows &) { throw 42; } + __host__ __device__ + CopyThrows &operator=(const CopyThrows &) { throw 42; } +}; + +struct CopyCannotThrow { + static int alive; + __host__ __device__ + CopyCannotThrow() { ++alive; } + __host__ __device__ + CopyCannotThrow(const CopyCannotThrow &) noexcept { ++alive; } + __host__ __device__ + CopyCannotThrow(CopyCannotThrow &&) noexcept { assert(false); } + __host__ __device__ + CopyCannotThrow &operator=(const CopyCannotThrow &) noexcept = default; + __host__ __device__ + CopyCannotThrow &operator=(CopyCannotThrow &&) noexcept { assert(false); return *this; } +}; + +int CopyCannotThrow::alive = 0; + +struct MoveThrows { + static int alive; + __host__ __device__ + MoveThrows() { ++alive; } + __host__ __device__ + MoveThrows(const MoveThrows &) { ++alive; } + __host__ __device__ + MoveThrows(MoveThrows &&) { throw 42; } + __host__ __device__ + MoveThrows &operator=(const MoveThrows &) { return *this; } + __host__ __device__ + MoveThrows &operator=(MoveThrows &&) { throw 42; } + __host__ __device__ + ~MoveThrows() { --alive; } +}; + +int MoveThrows::alive = 0; + +struct MakeEmptyT { + static int alive; + __host__ __device__ + MakeEmptyT() { ++alive; } + __host__ __device__ + MakeEmptyT(const MakeEmptyT &) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + __host__ __device__ + MakeEmptyT(MakeEmptyT &&) { throw 42; } + __host__ __device__ + MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } + __host__ __device__ + MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } + __host__ __device__ + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; + +__host__ __device__ +template void makeEmpty(Variant &v) { + Variant v2(cuda::std::in_place_type); + try { + v = cuda::std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +__host__ __device__ +void test_copy_assignment_not_noexcept() { + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_copy_assignable::value, ""); + } +} + +__host__ __device__ +void test_copy_assignment_sfinae() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_copy_assignable::value, ""); + } + + // Make sure we properly propagate triviality (see P0602R4). + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_trivially_copy_assignable::value, ""); + static_assert(cuda::std::is_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copy_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copy_assignable::value, ""); + } +} + +__host__ __device__ +void test_copy_assignment_empty_empty() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<0>); + makeEmpty(v1); + V v2(cuda::std::in_place_index<0>); + makeEmpty(v2); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == cuda::std::variant_npos); + } +#endif // TEST_HAS_NO_EXCEPTIONS +} + +__host__ __device__ +void test_copy_assignment_non_empty_empty() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::std::in_place_index<0>); + makeEmpty(v2); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == cuda::std::variant_npos); + } + /*{ + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<2>, "hello"); + V v2(cuda::std::in_place_index<0>); + makeEmpty(v2); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == cuda::std::variant_npos); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS +} + +__host__ __device__ +void test_copy_assignment_empty_non_empty() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<0>); + makeEmpty(v1); + V v2(cuda::std::in_place_index<0>, 42); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(cuda::std::get<0>(v1) == 42); + } + /*{ + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<0>); + makeEmpty(v1); + V v2(cuda::std::in_place_type, "hello"); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(cuda::std::get<2>(v1) == "hello"); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS +} + +template struct Result { size_t index; T value; }; + +__host__ __device__ +void test_copy_assignment_same_index() { + { + using V = cuda::std::variant; + V v1(43); + V v2(42); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(cuda::std::get<0>(v1) == 42); + } + { + using V = cuda::std::variant; + V v1(43l); + V v2(42l); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(cuda::std::get<1>(v1) == 42); + } + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_type, 43); + V v2(cuda::std::in_place_type, 42); + CopyAssign::reset(); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(cuda::std::get<1>(v1).value == 42); +#if !defined(TEST_COMPILER_MSVC) + assert(CopyAssign::copy_construct() == 0); + assert(CopyAssign::move_construct() == 0); + // FIXME(mdominiak): try to narrow down what in the compiler makes it emit an invalid PTX call instruction without this barrier + // this seems like it is not going to be a fun exercise trying to reproduce this in a minimal enough case that the compiler can fix it + // so I am leaving it with this workaround for now, as it seems to be a strange interactions of many weird things these tests are doing. + asm volatile ("" ::: "memory"); + assert(CopyAssign::copy_assign() == 1); +#endif // !TEST_COMPILER_MSVC + } +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + /*{ + using V = cuda::std::variant; + V v1(cuda::std::in_place_type); + MET &mref = cuda::std::get<1>(v1); + V v2(cuda::std::in_place_type); + try { + v1 = v2; + assert(false); + } catch (...) { + } + assert(v1.index() == 1); + assert(&cuda::std::get<1>(v1) == &mref); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS + + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(43); + V v2(42); + v = v2; + return {v.index(), cuda::std::get<0>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(43l); + V v2(42l); + v = v2; + return {v.index(), cuda::std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(cuda::std::in_place_type, 43); + V v2(cuda::std::in_place_type, 42); + v = v2; + return {v.index(), cuda::std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(cuda::std::in_place_type, 43); + V v2(cuda::std::in_place_type, 42); + v = v2; + return {v.index(), cuda::std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } +} + +__host__ __device__ +void test_copy_assignment_different_index() { + { + using V = cuda::std::variant; + V v1(43); + V v2(42l); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(cuda::std::get<1>(v1) == 42); + } + { + using V = cuda::std::variant; + CopyAssign::reset(); + V v1(cuda::std::in_place_type, 43u); + V v2(cuda::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(cuda::std::get<1>(v1).value == 42); +#if !defined(TEST_COMPILER_MSVC) + assert(CopyAssign::alive() == 2); + assert(CopyAssign::copy_construct() == 1); + assert(CopyAssign::move_construct() == 1); + // FIXME(mdominiak): try to narrow down what in the compiler makes it emit an invalid PTX call instruction without this barrier + // this seems like it is not going to be a fun exercise trying to reproduce this in a minimal enough case that the compiler can fix it + // so I am leaving it with this workaround for now, as it seems to be a strange interactions of many weird things these tests are doing. + asm volatile ("" ::: "memory"); + assert(CopyAssign::copy_assign() == 0); +#endif // !TEST_COMPILER_MSVC + } +#ifndef TEST_HAS_NO_EXCEPTIONS + /*{ + using V = cuda::std::variant; + V v1(cuda::std::in_place_type, "hello"); + V v2(cuda::std::in_place_type); + try { + v1 = v2; + assert(false); + } catch (...) { / * ... * / + } + // Test that copy construction is used directly if move construction may throw, + // resulting in a valueless variant if copy throws. + assert(v1.valueless_by_exception()); + } + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_type, "hello"); + V v2(cuda::std::in_place_type); + assert(MoveThrows::alive == 1); + // Test that copy construction is used directly if move construction may throw. + v1 = v2; + assert(v1.index() == 1); + assert(v2.index() == 1); + assert(MoveThrows::alive == 2); + } + { + // Test that direct copy construction is preferred when it cannot throw. + using V = cuda::std::variant; + V v1(cuda::std::in_place_type, "hello"); + V v2(cuda::std::in_place_type); + assert(CopyCannotThrow::alive == 1); + v1 = v2; + assert(v1.index() == 1); + assert(v2.index() == 1); + assert(CopyCannotThrow::alive == 2); + } + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_type); + V v2(cuda::std::in_place_type, "hello"); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(cuda::std::get<2>(v1) == "hello"); + assert(v2.index() == 2); + assert(cuda::std::get<2>(v2) == "hello"); + } + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_type); + V v2(cuda::std::in_place_type, "hello"); + V &vref = (v1 = v2); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(cuda::std::get<2>(v1) == "hello"); + assert(v2.index() == 2); + assert(cuda::std::get<2>(v2) == "hello"); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS + + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(43); + V v2(42l); + v = v2; + return {v.index(), cuda::std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(cuda::std::in_place_type, 43u); + V v2(cuda::std::in_place_type, 42); + v = v2; + return {v.index(), cuda::std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } +} + +template +__host__ __device__ +constexpr bool test_constexpr_assign_imp( + cuda::std::variant&& v, ValueType&& new_value) +{ + const cuda::std::variant cp( + cuda::std::forward(new_value)); + v = cp; + return v.index() == NewIdx && + cuda::std::get(v) == cuda::std::get(cp); +} + +__host__ __device__ +void test_constexpr_copy_assignment() { + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copyable::value, ""); + static_assert(cuda::std::is_trivially_copy_assignable::value, ""); + static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_imp<2>(V(42l), 101), ""); +} + +int main(int, char**) { + 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(); + test_constexpr_copy_assignment(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp new file mode 100644 index 0000000000..b3c41df6ec --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp @@ -0,0 +1,525 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// constexpr variant& operator=(variant&&) noexcept(see below); + +#include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct NoCopy { + NoCopy(const NoCopy &) = delete; + NoCopy &operator=(const NoCopy &) = default; +}; + +struct CopyOnly { + CopyOnly(const CopyOnly &) = default; + CopyOnly(CopyOnly &&) = delete; + CopyOnly &operator=(const CopyOnly &) = default; + CopyOnly &operator=(CopyOnly &&) = delete; +}; + +struct MoveOnly { + MoveOnly(const MoveOnly &) = delete; + MoveOnly(MoveOnly &&) = default; + MoveOnly &operator=(const MoveOnly &) = delete; + MoveOnly &operator=(MoveOnly &&) = default; +}; + +struct MoveOnlyNT { + MoveOnlyNT(const MoveOnlyNT &) = delete; + __host__ __device__ + MoveOnlyNT(MoveOnlyNT &&) {} + MoveOnlyNT &operator=(const MoveOnlyNT &) = delete; + MoveOnlyNT &operator=(MoveOnlyNT &&) = default; +}; + +struct MoveOnlyOddNothrow { + __host__ __device__ + MoveOnlyOddNothrow(MoveOnlyOddNothrow &&) noexcept(false) {} + MoveOnlyOddNothrow(const MoveOnlyOddNothrow &) = delete; + MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow &&) noexcept = default; + MoveOnlyOddNothrow &operator=(const MoveOnlyOddNothrow &) = delete; +}; + +struct MoveAssignOnly { + MoveAssignOnly(MoveAssignOnly &&) = delete; + MoveAssignOnly &operator=(MoveAssignOnly &&) = default; +}; + +struct MoveAssign { + STATIC_MEMBER_VAR(move_construct, int); + STATIC_MEMBER_VAR(move_assign, int); + __host__ __device__ + static void reset() { move_construct() = move_assign() = 0; } + __host__ __device__ + MoveAssign(int v) : value(v) {} + __host__ __device__ + MoveAssign(MoveAssign &&o) : value(o.value) { + ++move_construct(); + o.value = -1; + } + __host__ __device__ + MoveAssign &operator=(MoveAssign &&o) { + value = o.value; + ++move_assign(); + o.value = -1; + return *this; + } + int value; +}; + +struct NTMoveAssign { + __host__ __device__ + constexpr NTMoveAssign(int v) : value(v) {} + NTMoveAssign(const NTMoveAssign &) = default; + NTMoveAssign(NTMoveAssign &&) = default; + NTMoveAssign &operator=(const NTMoveAssign &that) = default; + __host__ __device__ + NTMoveAssign &operator=(NTMoveAssign &&that) { + value = that.value; + that.value = -1; + return *this; + }; + int value; +}; + +static_assert(!cuda::std::is_trivially_move_assignable::value, ""); +static_assert(cuda::std::is_move_assignable::value, ""); + +struct TMoveAssign { + __host__ __device__ + constexpr TMoveAssign(int v) : value(v) {} + TMoveAssign(const TMoveAssign &) = delete; + TMoveAssign(TMoveAssign &&) = default; + TMoveAssign &operator=(const TMoveAssign &) = delete; + TMoveAssign &operator=(TMoveAssign &&) = default; + int value; +}; + +static_assert(cuda::std::is_trivially_move_assignable::value, ""); + +struct TMoveAssignNTCopyAssign { + __host__ __device__ + constexpr TMoveAssignNTCopyAssign(int v) : value(v) {} + TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default; + TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default; + __host__ __device__ + TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) { + value = that.value; + return *this; + } + TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default; + int value; +}; + +static_assert(cuda::std::is_trivially_move_assignable_v, ""); + +struct TrivialCopyNontrivialMove { + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default; + __host__ __device__ + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {} + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default; + __host__ __device__ + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept { + return *this; + } +}; + +static_assert(cuda::std::is_trivially_copy_assignable_v, ""); +static_assert(!cuda::std::is_trivially_move_assignable_v, ""); + +__host__ __device__ +void test_move_assignment_noexcept() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_move_assignable::value, ""); + } +} + +__host__ __device__ +void test_move_assignment_sfinae() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_move_assignable::value, ""); + } + { + // variant only provides move assignment when the types also provide + // a move constructor. + using V = cuda::std::variant; + static_assert(!cuda::std::is_move_assignable::value, ""); + } + + // Make sure we properly propagate triviality (see P0602R4). + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_trivially_move_assignable::value, ""); + static_assert(cuda::std::is_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_trivially_move_assignable::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_move_assignable::value, ""); + } +} + +__host__ __device__ +void test_move_assignment_empty_empty() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<0>); + makeEmpty(v1); + V v2(cuda::std::in_place_index<0>); + makeEmpty(v2); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == cuda::std::variant_npos); + } +#endif // TEST_HAS_NO_EXCEPTIONS +} + +__host__ __device__ +void test_move_assignment_non_empty_empty() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::std::in_place_index<0>); + makeEmpty(v2); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == cuda::std::variant_npos); + } + /*{ + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<2>, "hello"); + V v2(cuda::std::in_place_index<0>); + makeEmpty(v2); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.valueless_by_exception()); + assert(v1.index() == cuda::std::variant_npos); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS +} + +__host__ __device__ +void test_move_assignment_empty_non_empty() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using MET = MakeEmptyT; + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<0>); + makeEmpty(v1); + V v2(cuda::std::in_place_index<0>, 42); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(cuda::std::get<0>(v1) == 42); + } + /*{ + using V = cuda::std::variant; + V v1(cuda::std::in_place_index<0>); + makeEmpty(v1); + V v2(cuda::std::in_place_type, "hello"); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(cuda::std::get<2>(v1) == "hello"); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS +} + +template struct Result { size_t index; T value; }; + +__host__ __device__ +void test_move_assignment_same_index() { + { + using V = cuda::std::variant; + V v1(43); + V v2(42); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 0); + assert(cuda::std::get<0>(v1) == 42); + } + { + using V = cuda::std::variant; + V v1(43l); + V v2(42l); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(cuda::std::get<1>(v1) == 42); + } + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_type, 43); + V v2(cuda::std::in_place_type, 42); + MoveAssign::reset(); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(cuda::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 = cuda::std::variant; + V v1(cuda::std::in_place_type); + MET &mref = cuda::std::get<1>(v1); + V v2(cuda::std::in_place_type); + try { + v1 = cuda::std::move(v2); + assert(false); + } catch (...) { + } + assert(v1.index() == 1); + assert(&cuda::std::get<1>(v1) == &mref); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS + + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(43); + V v2(42); + v = cuda::std::move(v2); + return {v.index(), cuda::std::get<0>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(43l); + V v2(42l); + v = cuda::std::move(v2); + return {v.index(), cuda::std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(cuda::std::in_place_type, 43); + V v2(cuda::std::in_place_type, 42); + v = cuda::std::move(v2); + return {v.index(), cuda::std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } +} + +__host__ __device__ +void test_move_assignment_different_index() { + { + using V = cuda::std::variant; + V v1(43); + V v2(42l); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(cuda::std::get<1>(v1) == 42); + } + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_type, 43u); + V v2(cuda::std::in_place_type, 42); + MoveAssign::reset(); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 1); + assert(cuda::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 = cuda::std::variant; + V v1(cuda::std::in_place_type); + V v2(cuda::std::in_place_type); + try { + v1 = cuda::std::move(v2); + assert(false); + } catch (...) { + } + assert(v1.valueless_by_exception()); + assert(v1.index() == cuda::std::variant_npos); + } + { + using V = cuda::std::variant; + V v1(cuda::std::in_place_type); + V v2(cuda::std::in_place_type, "hello"); + V &vref = (v1 = cuda::std::move(v2)); + assert(&vref == &v1); + assert(v1.index() == 2); + assert(cuda::std::get<2>(v1) == "hello"); + }*/ +#endif // TEST_HAS_NO_EXCEPTIONS + + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(43); + V v2(42l); + v = cuda::std::move(v2); + return {v.index(), cuda::std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + using V = cuda::std::variant; + V v(cuda::std::in_place_type, 43u); + V v2(cuda::std::in_place_type, 42); + v = cuda::std::move(v2); + return {v.index(), cuda::std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } +} + +template +__host__ __device__ +constexpr bool test_constexpr_assign_imp( + cuda::std::variant&& v, ValueType&& new_value) +{ + cuda::std::variant v2( + cuda::std::forward(new_value)); + const auto cp = v2; + v = cuda::std::move(v2); + return v.index() == NewIdx && + cuda::std::get(v) == cuda::std::get(cp); +} + +__host__ __device__ +void test_constexpr_move_assignment() { + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copyable::value, ""); + static_assert(cuda::std::is_trivially_move_assignable::value, ""); + static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_imp<2>(V(42l), 101), ""); +} + +int main(int, char**) { + 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(); + test_constexpr_move_assignment(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp new file mode 100644 index 0000000000..efec51fa23 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp @@ -0,0 +1,220 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template constexpr variant(T&&) noexcept(see below); + +#include +// #include +#include +#include +// #include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct Dummy { + Dummy() = default; +}; + +struct ThrowsT { + __host__ __device__ + ThrowsT(int) noexcept(false) {} +}; + +struct NoThrowT { + __host__ __device__ + NoThrowT(int) noexcept(true) {} +}; + +struct AnyConstructible { template __host__ __device__ AnyConstructible(T&&) {} }; +struct NoConstructible { NoConstructible() = delete; }; +template +struct RValueConvertibleFrom { __host__ __device__ RValueConvertibleFrom(T&&) {} }; + +__host__ __device__ +void test_T_ctor_noexcept() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_constructible::value, ""); + } +} + +__host__ __device__ +void test_T_ctor_sfinae() { + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_constructible::value, "ambiguous"); + } + /* { + using V = cuda::std::variant; + static_assert(!cuda::std::is_constructible::value, "ambiguous"); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_constructible::value, + "no matching constructor"); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_constructible::value == VariantAllowsNarrowingConversions, + "no matching constructor"); + } + { + using V = cuda::std::variant, bool>; + static_assert(!cuda::std::is_constructible>::value, + "no explicit bool in constructor"); + struct X { + __host__ __device__ operator void*(); + }; + static_assert(!cuda::std::is_constructible::value, + "no boolean conversion in constructor"); + static_assert(!cuda::std::is_constructible::value, + "no converted to bool in constructor"); + } */ + { + struct X {}; + struct Y { + __host__ __device__ operator X(); + }; + using V = cuda::std::variant; + static_assert(cuda::std::is_constructible::value, + "regression on user-defined conversions in constructor"); + } + { + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible>::value, + "no matching constructor"); + static_assert(!cuda::std::is_constructible>::value, + "no matching constructor"); + } + + + +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_constructible::value, "ambiguous"); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_constructible::value, "ambiguous"); + } +#endif +} + +__host__ __device__ +void test_T_ctor_basic() { + { + constexpr cuda::std::variant v(42); + static_assert(v.index() == 0, ""); + static_assert(cuda::std::get<0>(v) == 42, ""); + } + { + constexpr cuda::std::variant v(42l); + static_assert(v.index() == 1, ""); + static_assert(cuda::std::get<1>(v) == 42, ""); + } +#ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS + { + constexpr cuda::std::variant v(42); + static_assert(v.index() == 1, ""); + static_assert(cuda::std::get<1>(v) == 42, ""); + } +#endif + /* { + cuda::std::variant v = "foo"; + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == "foo"); + } + { + cuda::std::variant> v = nullptr; + assert(v.index() == 1); + assert(cuda::std::get<1>(v) == nullptr); + } */ + { + cuda::std::variant v = true; + assert(v.index() == 0); + assert(cuda::std::get<0>(v)); + } + { + cuda::std::variant> v1 = 42; + assert(v1.index() == 0); + + int x = 42; + cuda::std::variant, AnyConstructible> v2 = x; + assert(v2.index() == 1); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + static_assert(cuda::std::is_convertible::value, "must be implicit"); + int x = 42; + V v(x); + assert(v.index() == 0); + assert(&cuda::std::get<0>(v) == &x); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_convertible::value, "must be implicit"); + int x = 42; + V v(cuda::std::move(x)); + assert(v.index() == 1); + assert(&cuda::std::get<1>(v) == &x); + } +#endif +} + +struct BoomOnAnything { + template + __host__ __device__ + constexpr BoomOnAnything(T) { static_assert(!cuda::std::is_same::value, ""); } +}; + +__host__ __device__ +void test_no_narrowing_check_for_class_types() { + using V = cuda::std::variant; + V v(42); + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == 42); +} + +struct Bar {}; +struct Baz {}; +__host__ __device__ +void test_construction_with_repeated_types() { + using V = cuda::std::variant; + static_assert(!cuda::std::is_constructible::value, ""); + static_assert(!cuda::std::is_constructible::value, ""); + // OK, the selected type appears only once and so it shouldn't + // be affected by the duplicate types. + static_assert(cuda::std::is_constructible::value, ""); +} + +int main(int, char**) { + test_T_ctor_basic(); + test_T_ctor_noexcept(); + test_T_ctor_sfinae(); + test_no_narrowing_check_for_class_types(); + test_construction_with_repeated_types(); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp new file mode 100644 index 0000000000..9946a293b3 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + +// template constexpr variant(T&&) noexcept(see below); + +#include +// #include +// #include + +#include "variant_test_helpers.h" + +int main(int, char**) +{ + static_assert(!cuda::std::is_constructible, int>::value, ""); + static_assert(!cuda::std::is_constructible, int>::value, ""); + static_assert(cuda::std::is_constructible, int>::value == VariantAllowsNarrowingConversions, ""); + + // static_assert(cuda::std::is_constructible, int>::value == VariantAllowsNarrowingConversions, ""); + // static_assert(cuda::std::is_constructible, int>::value == VariantAllowsNarrowingConversions, ""); + // static_assert(!cuda::std::is_constructible, int>::value, ""); + + static_assert(!cuda::std::is_constructible, decltype("meow")>::value, ""); + static_assert(!cuda::std::is_constructible, decltype("meow")>::value, ""); + static_assert(!cuda::std::is_constructible, decltype("meow")>::value, ""); + + static_assert(!cuda::std::is_constructible, cuda::std::true_type>::value, ""); + // static_assert(!cuda::std::is_constructible, cuda::std::unique_ptr >::value, ""); + static_assert(!cuda::std::is_constructible, decltype(nullptr)>::value, ""); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp new file mode 100644 index 0000000000..ed73a12e15 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -0,0 +1,278 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// constexpr variant(variant const&); + +#include +#include +#include + +#include "test_macros.h" +#include "test_workarounds.h" + +struct NonT { + __host__ __device__ + NonT(int v) : value(v) {} + __host__ __device__ + NonT(const NonT &o) : value(o.value) {} + int value; +}; +static_assert(!cuda::std::is_trivially_copy_constructible::value, ""); + +struct NoCopy { + NoCopy(const NoCopy &) = delete; +}; + +struct MoveOnly { + MoveOnly(const MoveOnly &) = delete; + MoveOnly(MoveOnly &&) = default; +}; + +struct MoveOnlyNT { + MoveOnlyNT(const MoveOnlyNT &) = delete; + __host__ __device__ + MoveOnlyNT(MoveOnlyNT &&) {} +}; + +struct NTCopy { + __host__ __device__ + constexpr NTCopy(int v) : value(v) {} + __host__ __device__ + NTCopy(const NTCopy &that) : value(that.value) {} + NTCopy(NTCopy &&) = delete; + int value; +}; + +static_assert(!cuda::std::is_trivially_copy_constructible::value, ""); +static_assert(cuda::std::is_copy_constructible::value, ""); + +struct TCopy { + __host__ __device__ + constexpr TCopy(int v) : value(v) {} + TCopy(TCopy const &) = default; + TCopy(TCopy &&) = delete; + int value; +}; + +static_assert(cuda::std::is_trivially_copy_constructible::value, ""); + +struct TCopyNTMove { + __host__ __device__ + constexpr TCopyNTMove(int v) : value(v) {} + TCopyNTMove(const TCopyNTMove&) = default; + __host__ __device__ + TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; } + int value; +}; + +static_assert(cuda::std::is_trivially_copy_constructible::value, ""); + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + static int alive; + __host__ __device__ + MakeEmptyT() { ++alive; } + __host__ __device__ + MakeEmptyT(const MakeEmptyT &) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + __host__ __device__ + MakeEmptyT(MakeEmptyT &&) { throw 42; } + __host__ __device__ + MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } + __host__ __device__ + MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } + __host__ __device__ + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; +__host__ __device__ +template void makeEmpty(Variant &v) { + Variant v2(cuda::std::in_place_type); + try { + v = cuda::std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +__host__ __device__ +void test_copy_ctor_sfinae() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_copy_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_copy_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_copy_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_copy_constructible::value, ""); + } + + // Make sure we properly propagate triviality (see P0602R4). + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copy_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_trivially_copy_constructible::value, ""); + static_assert(cuda::std::is_copy_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copy_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_copy_constructible::value, ""); + } +} + +__host__ __device__ +void test_copy_ctor_basic() { + { + cuda::std::variant v(cuda::std::in_place_index<0>, 42); + cuda::std::variant v2 = v; + assert(v2.index() == 0); + assert(cuda::std::get<0>(v2) == 42); + } + { + cuda::std::variant v(cuda::std::in_place_index<1>, 42); + cuda::std::variant v2 = v; + assert(v2.index() == 1); + assert(cuda::std::get<1>(v2) == 42); + } + { + cuda::std::variant v(cuda::std::in_place_index<0>, 42); + assert(v.index() == 0); + cuda::std::variant v2(v); + printf("%d\n", (int)v2.index()); + assert(v2.index() == 0); + //assert(cuda::std::get<0>(v2).value == 42); + } + { + cuda::std::variant v(cuda::std::in_place_index<1>, 42); + assert(v.index() == 1); + cuda::std::variant v2(v); + //assert(v2.index() == 1); + //assert(cuda::std::get<1>(v2).value == 42); + } + + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + { + constexpr cuda::std::variant v(cuda::std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr cuda::std::variant v2 = v; + static_assert(v2.index() == 0, ""); + static_assert(cuda::std::get<0>(v2) == 42, ""); + } + { + constexpr cuda::std::variant v(cuda::std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr cuda::std::variant v2 = v; + static_assert(v2.index() == 1, ""); + static_assert(cuda::std::get<1>(v2) == 42, ""); + } + { + constexpr cuda::std::variant v(cuda::std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr cuda::std::variant v2(v); + static_assert(v2.index() == 0, ""); + static_assert(cuda::std::get<0>(v2).value == 42, ""); + } + { + constexpr cuda::std::variant v(cuda::std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr cuda::std::variant v2(v); + static_assert(v2.index() == 1, ""); + static_assert(cuda::std::get<1>(v2).value == 42, ""); + } + { + constexpr cuda::std::variant v(cuda::std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr cuda::std::variant v2(v); + static_assert(v2.index() == 0, ""); + static_assert(cuda::std::get<0>(v2).value == 42, ""); + } + { + constexpr cuda::std::variant v(cuda::std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr cuda::std::variant v2(v); + static_assert(v2.index() == 1, ""); + static_assert(cuda::std::get<1>(v2).value == 42, ""); + } +} + +__host__ __device__ +void test_copy_ctor_valueless_by_exception() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = cuda::std::variant; + V v1; + makeEmpty(v1); + const V &cv1 = v1; + V v(cv1); + assert(v.valueless_by_exception()); +#endif // TEST_HAS_NO_EXCEPTIONS +} + +template +__host__ __device__ +constexpr bool test_constexpr_copy_ctor_imp(cuda::std::variant const& v) { + auto v2 = v; + return v2.index() == v.index() && + v2.index() == Idx && + cuda::std::get(v2) == cuda::std::get(v); +} + +__host__ __device__ +void test_constexpr_copy_ctor() { + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + using V = cuda::std::variant; +#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE + static_assert(cuda::std::is_trivially_destructible::value, ""); + static_assert(cuda::std::is_trivially_copy_constructible::value, ""); + static_assert(cuda::std::is_trivially_move_constructible::value, ""); + static_assert(!cuda::std::is_copy_assignable::value, ""); + static_assert(!cuda::std::is_move_assignable::value, ""); +#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE + static_assert(cuda::std::is_trivially_copyable::value, ""); +#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE + static_assert(test_constexpr_copy_ctor_imp<0>(V(42l)), ""); + static_assert(test_constexpr_copy_ctor_imp<1>(V(nullptr)), ""); + static_assert(test_constexpr_copy_ctor_imp<2>(V(101)), ""); +} + +int main(int, char**) { + test_copy_ctor_basic(); + test_copy_ctor_valueless_by_exception(); + test_copy_ctor_sfinae(); + test_constexpr_copy_ctor(); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp new file mode 100644 index 0000000000..974cae488d --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/default.pass.cpp @@ -0,0 +1,134 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// constexpr variant() noexcept(see below); + +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct NonDefaultConstructible { + __host__ __device__ + constexpr NonDefaultConstructible(int) {} +}; + +struct NotNoexcept { + __host__ __device__ + NotNoexcept() noexcept(false) {} +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct DefaultCtorThrows { + __host__ __device__ + DefaultCtorThrows() { throw 42; } +}; +#endif + +__host__ __device__ +void test_default_ctor_sfinae() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_default_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_default_constructible::value, ""); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_default_constructible::value, ""); + } +#endif +} + +__host__ __device__ +void test_default_ctor_noexcept() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_default_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_default_constructible::value, ""); + } +} + +__host__ __device__ +void test_default_ctor_throws() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = cuda::std::variant; + try { + V v; + assert(false); + } catch (const int &ex) { + assert(ex == 42); + } catch (...) { + assert(false); + } +#endif +} + +__host__ __device__ +void test_default_ctor_basic() { + { + cuda::std::variant v; + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == 0); + } + { + cuda::std::variant v; + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == 0); + } + { + cuda::std::variant v; + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == 0); + } + { + using V = cuda::std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + static_assert(cuda::std::get<0>(v) == 0, ""); + } + { + using V = cuda::std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + static_assert(cuda::std::get<0>(v) == 0, ""); + } + { + using V = cuda::std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + static_assert(cuda::std::get<0>(v) == 0, ""); + } +} + +int main(int, char**) { + test_default_ctor_basic(); + test_default_ctor_sfinae(); + test_default_ctor_noexcept(); + test_default_ctor_throws(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_index_args.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_index_args.pass.cpp new file mode 100644 index 0000000000..a7e9cba9fd --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_index_args.pass.cpp @@ -0,0 +1,108 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template +// constexpr explicit variant(in_place_index_t, Args&&...); + +#include +#include +#include + +#include "test_convertible.h" +#include "test_macros.h" + +__host__ __device__ +void test_ctor_sfinae() { + { + using V = cuda::std::variant; + static_assert( + cuda::std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = cuda::std::variant; + static_assert( + cuda::std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = cuda::std::variant; + static_assert( + cuda::std::is_constructible, int *>::value, ""); + static_assert(!test_convertible, int *>(), ""); + } + { // args not convertible to type + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, int *>::value, ""); + static_assert(!test_convertible, int *>(), ""); + } + { // index not in variant + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } +} + +__host__ __device__ +void test_ctor_basic() { + { + constexpr cuda::std::variant v(cuda::std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + static_assert(cuda::std::get<0>(v) == 42, ""); + } + { + constexpr cuda::std::variant v(cuda::std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + static_assert(cuda::std::get<1>(v) == 42, ""); + } + { + constexpr cuda::std::variant v(cuda::std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + static_assert(cuda::std::get<1>(v) == 42, ""); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::in_place_index<0>, x); + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::in_place_index<1>, x); + assert(v.index() == 1); + assert(cuda::std::get<1>(v) == x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::in_place_index<2>, x); + assert(v.index() == 2); + assert(cuda::std::get<2>(v) == x); + } +} + +int main(int, char**) { + test_ctor_basic(); + test_ctor_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_args.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_args.pass.cpp new file mode 100644 index 0000000000..2c15de4603 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_index_init_list_args.pass.cpp @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template +// constexpr explicit +// variant(in_place_index_t, initializer_list, Args&&...); + +#include +#include +#include + +#include "test_convertible.h" +#include "test_macros.h" + +struct InitList { + cuda::std::size_t size; + __host__ __device__ + constexpr InitList(cuda::std::initializer_list il) : size(il.size()) {} +}; + +struct InitListArg { + cuda::std::size_t size; + int value; + __host__ __device__ + constexpr InitListArg(cuda::std::initializer_list il, int v) + : size(il.size()), value(v) {} +}; + +__host__ __device__ +void test_ctor_sfinae() { + using IL = cuda::std::initializer_list; + { // just init list + using V = cuda::std::variant; + static_assert(cuda::std::is_constructible, IL>::value, + ""); + static_assert(!test_convertible, IL>(), ""); + } + { // too many arguments + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, IL, int>::value, + ""); + static_assert(!test_convertible, IL, int>(), + ""); + } + { // too few arguments + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // init list and arguments + using V = cuda::std::variant; + static_assert( + cuda::std::is_constructible, IL, int>::value, ""); + static_assert(!test_convertible, IL, int>(), + ""); + } + { // not constructible from arguments + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // index not in variant + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } +} + +__host__ __device__ +void test_ctor_basic() { + { + constexpr cuda::std::variant v( + cuda::std::in_place_index<0>, {1, 2, 3}); + static_assert(v.index() == 0, ""); + static_assert(cuda::std::get<0>(v).size == 3, ""); + } + { + constexpr cuda::std::variant v( + cuda::std::in_place_index<2>, {1, 2, 3}); + static_assert(v.index() == 2, ""); + static_assert(cuda::std::get<2>(v).size == 3, ""); + } + { + constexpr cuda::std::variant v( + cuda::std::in_place_index<1>, {1, 2, 3, 4}, 42); + static_assert(v.index() == 1, ""); + static_assert(cuda::std::get<1>(v).size == 4, ""); + static_assert(cuda::std::get<1>(v).value == 42, ""); + } +} + +int main(int, char**) { + test_ctor_basic(); + test_ctor_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_type_args.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_type_args.pass.cpp new file mode 100644 index 0000000000..2b295414b7 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_type_args.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template +// constexpr explicit variant(in_place_type_t, Args&&...); + +#include +#include +#include + +#include "test_convertible.h" +#include "test_macros.h" + +__host__ __device__ +void test_ctor_sfinae() { + { + using V = cuda::std::variant; + static_assert( + cuda::std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = cuda::std::variant; + static_assert( + cuda::std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { + using V = cuda::std::variant; + static_assert( + cuda::std::is_constructible, int *>::value, + ""); + static_assert(!test_convertible, int *>(), + ""); + } + { // duplicate type + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, int>::value, ""); + static_assert(!test_convertible, int>(), ""); + } + { // args not convertible to type + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, int *>::value, ""); + static_assert(!test_convertible, int *>(), ""); + } + { // type not in variant + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, int>::value, + ""); + static_assert(!test_convertible, int>(), + ""); + } +} + +__host__ __device__ +void test_ctor_basic() { + { + constexpr cuda::std::variant v(cuda::std::in_place_type, 42); + static_assert(v.index() == 0, ""); + static_assert(cuda::std::get<0>(v) == 42, ""); + } + { + constexpr cuda::std::variant v(cuda::std::in_place_type, 42); + static_assert(v.index() == 1, ""); + static_assert(cuda::std::get<1>(v) == 42, ""); + } + { + constexpr cuda::std::variant v( + cuda::std::in_place_type, 42); + static_assert(v.index() == 1, ""); + static_assert(cuda::std::get<1>(v) == 42, ""); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::in_place_type, x); + assert(v.index() == 0); + assert(cuda::std::get<0>(v) == x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::in_place_type, x); + assert(v.index() == 1); + assert(cuda::std::get<1>(v) == x); + } + { + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::in_place_type, x); + assert(v.index() == 2); + assert(cuda::std::get<2>(v) == x); + } +} + +int main(int, char**) { + test_ctor_basic(); + test_ctor_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_args.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_args.pass.cpp new file mode 100644 index 0000000000..e0e4954240 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/in_place_type_init_list_args.pass.cpp @@ -0,0 +1,117 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template +// constexpr explicit +// variant(in_place_type_t, initializer_list, Args&&...); + +#include +#include +#include + +#include "test_convertible.h" +#include "test_macros.h" + +struct InitList { + cuda::std::size_t size; + __host__ __device__ + constexpr InitList(cuda::std::initializer_list il) : size(il.size()) {} +}; + +struct InitListArg { + cuda::std::size_t size; + int value; + __host__ __device__ + constexpr InitListArg(cuda::std::initializer_list il, int v) + : size(il.size()), value(v) {} +}; + +__host__ __device__ +void test_ctor_sfinae() { + using IL = cuda::std::initializer_list; + { // just init list + using V = cuda::std::variant; + static_assert( + cuda::std::is_constructible, IL>::value, + ""); + static_assert(!test_convertible, IL>(), + ""); + } + { // too many arguments + using V = cuda::std::variant; + static_assert(!cuda::std::is_constructible, IL, + int>::value, + ""); + static_assert( + !test_convertible, IL, int>(), ""); + } + { // too few arguments + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, IL>::value, + ""); + static_assert(!test_convertible, IL>(), + ""); + } + { // init list and arguments + using V = cuda::std::variant; + static_assert(cuda::std::is_constructible, + IL, int>::value, + ""); + static_assert( + !test_convertible, IL, int>(), ""); + } + { // not constructible from arguments + using V = cuda::std::variant; + static_assert( + !cuda::std::is_constructible, IL>::value, ""); + static_assert(!test_convertible, IL>(), ""); + } + { // duplicate types in variant + using V = cuda::std::variant; + static_assert(!cuda::std::is_constructible, + IL, int>::value, + ""); + static_assert( + !test_convertible, IL, int>(), ""); + } +} + +__host__ __device__ +void test_ctor_basic() { + { + constexpr cuda::std::variant v( + cuda::std::in_place_type, {1, 2, 3}); + static_assert(v.index() == 0, ""); + static_assert(cuda::std::get<0>(v).size == 3, ""); + } + { + constexpr cuda::std::variant v( + cuda::std::in_place_type, {1, 2, 3, 4}, 42); + static_assert(v.index() == 1, ""); + static_assert(cuda::std::get<1>(v).size == 4, ""); + static_assert(cuda::std::get<1>(v).value == 42, ""); + } +} + +int main(int, char**) { + test_ctor_basic(); + test_ctor_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp new file mode 100644 index 0000000000..236be78c66 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp @@ -0,0 +1,358 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// constexpr variant(variant&&) noexcept(see below); + +#include +#include +#include + +#include "test_macros.h" +#include "test_workarounds.h" + +struct ThrowsMove { + __host__ __device__ + ThrowsMove(ThrowsMove &&) noexcept(false) {} +}; + +struct NoCopy { + NoCopy(const NoCopy &) = delete; +}; + +struct MoveOnly { + int value; + __host__ __device__ + MoveOnly(int v) : value(v) {} + MoveOnly(const MoveOnly &) = delete; + MoveOnly(MoveOnly &&) = default; +}; + +struct MoveOnlyNT { + int value; + __host__ __device__ + MoveOnlyNT(int v) : value(v) {} + MoveOnlyNT(const MoveOnlyNT &) = delete; + __host__ __device__ + MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; } +}; + +struct NTMove { + __host__ __device__ + constexpr NTMove(int v) : value(v) {} + NTMove(const NTMove &) = delete; + __host__ __device__ + NTMove(NTMove &&that) : value(that.value) { that.value = -1; } + int value; +}; + +static_assert(!cuda::std::is_trivially_move_constructible::value, ""); +static_assert(cuda::std::is_move_constructible::value, ""); + +struct TMove { + __host__ __device__ + constexpr TMove(int v) : value(v) {} + TMove(const TMove &) = delete; + TMove(TMove &&) = default; + int value; +}; + +static_assert(cuda::std::is_trivially_move_constructible::value, ""); + +struct TMoveNTCopy { + __host__ __device__ + constexpr TMoveNTCopy(int v) : value(v) {} + __host__ __device__ + TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {} + TMoveNTCopy(TMoveNTCopy&&) = default; + int value; +}; + +static_assert(cuda::std::is_trivially_move_constructible::value, ""); + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct MakeEmptyT { + static int alive; + __host__ __device__ + MakeEmptyT() { ++alive; } + __host__ __device__ + MakeEmptyT(const MakeEmptyT &) { + ++alive; + // Don't throw from the copy constructor since variant's assignment + // operator performs a copy before committing to the assignment. + } + __host__ __device__ + MakeEmptyT(MakeEmptyT &&) { throw 42; } + __host__ __device__ + MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } + __host__ __device__ + MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } + __host__ __device__ + ~MakeEmptyT() { --alive; } +}; + +int MakeEmptyT::alive = 0; + +__host__ __device__ +template void makeEmpty(Variant &v) { + Variant v2(cuda::std::in_place_type); + try { + v = cuda::std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +__host__ __device__ +void test_move_noexcept() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_nothrow_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_nothrow_move_constructible::value, ""); + } +} + +__host__ __device__ +void test_move_ctor_sfinae() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_move_constructible::value, ""); + } + + // Make sure we properly propagate triviality (see P0602R4). + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_trivially_move_constructible::value, ""); + static_assert(cuda::std::is_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_move_constructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_move_constructible::value, ""); + } +} + +template +struct Result { size_t index; T value; }; + +__host__ __device__ +void test_move_ctor_basic() { + { + cuda::std::variant v(cuda::std::in_place_index<0>, 42); + cuda::std::variant v2 = cuda::std::move(v); + assert(v2.index() == 0); + assert(cuda::std::get<0>(v2) == 42); + } + { + cuda::std::variant v(cuda::std::in_place_index<1>, 42); + cuda::std::variant v2 = cuda::std::move(v); + assert(v2.index() == 1); + assert(cuda::std::get<1>(v2) == 42); + } + { + cuda::std::variant v(cuda::std::in_place_index<0>, 42); + assert(v.index() == 0); + cuda::std::variant v2(cuda::std::move(v)); + assert(v2.index() == 0); + assert(cuda::std::get<0>(v2).value == 42); + } + { + cuda::std::variant v(cuda::std::in_place_index<1>, 42); + assert(v.index() == 1); + cuda::std::variant v2(cuda::std::move(v)); + assert(v2.index() == 1); + assert(cuda::std::get<1>(v2).value == 42); + } + { + cuda::std::variant v(cuda::std::in_place_index<0>, 42); + assert(v.index() == 0); + cuda::std::variant v2(cuda::std::move(v)); + assert(v2.index() == 0); + assert(cuda::std::get<0>(v).value == -1); + assert(cuda::std::get<0>(v2).value == 42); + } + { + cuda::std::variant v(cuda::std::in_place_index<1>, 42); + assert(v.index() == 1); + cuda::std::variant v2(cuda::std::move(v)); + assert(v2.index() == 1); + assert(cuda::std::get<1>(v).value == -1); + assert(cuda::std::get<1>(v2).value == 42); + } + + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + { + struct { + __host__ __device__ + constexpr Result operator()() const { + cuda::std::variant v(cuda::std::in_place_index<0>, 42); + cuda::std::variant v2 = cuda::std::move(v); + return {v2.index(), cuda::std::get<0>(cuda::std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + cuda::std::variant v(cuda::std::in_place_index<1>, 42); + cuda::std::variant v2 = cuda::std::move(v); + return {v2.index(), cuda::std::get<1>(cuda::std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + cuda::std::variant v(cuda::std::in_place_index<0>, 42); + cuda::std::variant v2(cuda::std::move(v)); + return {v2.index(), cuda::std::get<0>(cuda::std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + cuda::std::variant v(cuda::std::in_place_index<1>, 42); + cuda::std::variant v2(cuda::std::move(v)); + return {v2.index(), cuda::std::get<1>(cuda::std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + cuda::std::variant v(cuda::std::in_place_index<0>, 42); + cuda::std::variant v2(cuda::std::move(v)); + return {v2.index(), cuda::std::get<0>(cuda::std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + __host__ __device__ + constexpr Result operator()() const { + cuda::std::variant v(cuda::std::in_place_index<1>, 42); + cuda::std::variant v2(cuda::std::move(v)); + return {v2.index(), cuda::std::get<1>(cuda::std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value.value == 42, ""); + } +} + +__host__ __device__ +void test_move_ctor_valueless_by_exception() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = cuda::std::variant; + V v1; + makeEmpty(v1); + V v(cuda::std::move(v1)); + assert(v.valueless_by_exception()); +#endif // TEST_HAS_NO_EXCEPTIONS +} + +template +__host__ __device__ +constexpr bool test_constexpr_ctor_imp(cuda::std::variant const& v) { + auto copy = v; + auto v2 = cuda::std::move(copy); + return v2.index() == v.index() && + v2.index() == Idx && + cuda::std::get(v2) == cuda::std::get(v); +} + +__host__ __device__ +void test_constexpr_move_ctor() { + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). + using V = cuda::std::variant; +#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE + static_assert(cuda::std::is_trivially_destructible::value, ""); + static_assert(cuda::std::is_trivially_copy_constructible::value, ""); + static_assert(cuda::std::is_trivially_move_constructible::value, ""); + static_assert(!cuda::std::is_copy_assignable::value, ""); + static_assert(!cuda::std::is_move_assignable::value, ""); +#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE + static_assert(cuda::std::is_trivially_copyable::value, ""); +#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE + static_assert(cuda::std::is_trivially_move_constructible::value, ""); + static_assert(test_constexpr_ctor_imp<0>(V(42l)), ""); + static_assert(test_constexpr_ctor_imp<1>(V(nullptr)), ""); + static_assert(test_constexpr_ctor_imp<2>(V(101)), ""); +} + +int main(int, char**) { + test_move_ctor_basic(); + test_move_ctor_valueless_by_exception(); + test_move_noexcept(); + test_move_ctor_sfinae(); + test_constexpr_move_ctor(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp new file mode 100644 index 0000000000..3e88116207 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + +// ~variant(); + +#include +#include +#include + +#include "test_macros.h" + +struct NonTDtor { + STATIC_MEMBER_VAR(count, int); + NonTDtor() = default; + __host__ __device__ + ~NonTDtor() { ++count(); } +}; +static_assert(!cuda::std::is_trivially_destructible::value, ""); + +struct NonTDtor1 { + STATIC_MEMBER_VAR(count, int); + NonTDtor1() = default; + __host__ __device__ + ~NonTDtor1() { ++count(); } +}; +static_assert(!cuda::std::is_trivially_destructible::value, ""); + +struct TDtor { + __host__ __device__ TDtor(const TDtor &) {} // non-trivial copy + ~TDtor() = default; +}; +static_assert(!cuda::std::is_trivially_copy_constructible::value, ""); +static_assert(cuda::std::is_trivially_destructible::value, ""); + +int main(int, char**) { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_trivially_destructible::value, ""); + } + { + using V = cuda::std::variant; + static_assert(!cuda::std::is_trivially_destructible::value, ""); + { + V v(cuda::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(cuda::std::in_place_index<1>); } + assert(NonTDtor::count() == 0); + assert(NonTDtor1::count() == 0); + { + V v(cuda::std::in_place_index<2>); + assert(NonTDtor::count() == 0); + assert(NonTDtor1::count() == 0); + } + assert(NonTDtor::count() == 0); + assert(NonTDtor1::count() == 1); + } + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp new file mode 100644 index 0000000000..612a0b212e --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp @@ -0,0 +1,166 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template +// variant_alternative_t>& emplace(Args&&... args); + +#include +// #include +#include +#include + +#include "archetypes.h" +#include "test_convertible.h" +#include "test_macros.h" +#include "variant_test_helpers.h" + +template +__host__ __device__ +constexpr auto test_emplace_exists_imp(int) -> decltype( + cuda::std::declval().template emplace(cuda::std::declval()...), true) { + return true; +} + +template +__host__ __device__ +constexpr auto test_emplace_exists_imp(long) -> bool { + return false; +} + +template __host__ __device__ constexpr bool emplace_exists() { + return test_emplace_exists_imp(0); +} + +__host__ __device__ +void test_emplace_sfinae() { + { + using V = cuda::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 = cuda::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 +} + +__host__ __device__ +void test_basic() { + { + using V = cuda::std::variant; + V v(42); + auto& ref1 = v.emplace<0>(); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<0>(v) == 0); + assert(&ref1 == &cuda::std::get<0>(v)); + auto& ref2 = v.emplace<0>(42); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<0>(v) == 42); + assert(&ref2 == &cuda::std::get<0>(v)); + } + { + using V = + cuda::std::variant; //, cuda::std::string>; + const int x = 100; + V v(cuda::std::in_place_index<0>, -1); + // default emplace a value + auto& ref1 = v.emplace<1>(); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<1>(v) == 0); + assert(&ref1 == &cuda::std::get<1>(v)); + auto& ref2 = v.emplace<2>(&x); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<2>(v) == &x); + assert(&ref2 == &cuda::std::get<2>(v)); + // emplace with multiple args + /* auto& ref3 = v.emplace<4>(3u, 'a'); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<4>(v) == "aaa"); + assert(&ref3 == &cuda::std::get<4>(v));*/ + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant;//, + // cuda::std::string>; + const int x = 100; + int y = 42; + int z = 43; + V v(cuda::std::in_place_index<0>, -1); + // default emplace a value + auto& ref1 = v.emplace<1>(); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<1>(v) == 0); + assert(&ref1 == &cuda::std::get<1>(v)); + // emplace a reference + auto& ref2 = v.emplace<2>(x); + static_assert(cuda::std::is_same_v<&, decltype(ref)>, ""); + assert(&cuda::std::get<2>(v) == &x); + assert(&ref2 == &cuda::std::get<2>(v)); + // emplace an rvalue reference + auto& ref3 = v.emplace<3>(cuda::std::move(y)); + static_assert(cuda::std::is_same_v<&, decltype(ref)>, ""); + assert(&cuda::std::get<3>(v) == &y); + assert(&ref3 == &cuda::std::get<3>(v)); + // re-emplace a new reference over the active member + auto& ref4 = v.emplace<3>(cuda::std::move(z)); + static_assert(cuda::std::is_same_v<&, decltype(ref)>, ""); + assert(&cuda::std::get<3>(v) == &z); + assert(&ref4 == &cuda::std::get<3>(v)); + // emplace with multiple args + /*auto& ref5 = v.emplace<5>(3u, 'a'); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<5>(v) == "aaa"); + assert(&ref5 == &cuda::std::get<5>(v));*/ + } +#endif +} + +int main(int, char**) { + test_basic(); + test_emplace_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp new file mode 100644 index 0000000000..b735ca01bd --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template +// variant_alternative_t>& emplace(initializer_list il,Args&&... args); + +#include +// #include +#include +#include + +#include "archetypes.h" +#include "test_convertible.h" +#include "test_macros.h" + +struct InitList { + cuda::std::size_t size; + __host__ __device__ + constexpr InitList(cuda::std::initializer_list il) : size(il.size()) {} +}; + +struct InitListArg { + cuda::std::size_t size; + int value; + __host__ __device__ + constexpr InitListArg(cuda::std::initializer_list il, int v) + : size(il.size()), value(v) {} +}; + +template +__host__ __device__ +constexpr auto test_emplace_exists_imp(int) -> decltype( + cuda::std::declval().template emplace(cuda::std::declval()...), true) { + return true; +} + +template +__host__ __device__ +constexpr auto test_emplace_exists_imp(long) -> bool { + return false; +} + +template __host__ __device__ constexpr bool emplace_exists() { + return test_emplace_exists_imp(0); +} + +__host__ __device__ +void test_emplace_sfinae() { + using V = + cuda::std::variant; + using IL = cuda::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"); +} + +__host__ __device__ +void test_basic() { + using V = cuda::std::variant; + V v; + auto& ref1 = v.emplace<1>({1, 2, 3}); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<1>(v).size == 3); + assert(&ref1 == &cuda::std::get<1>(v)); + auto& ref2 = v.emplace<2>({1, 2, 3, 4}, 42); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<2>(v).size == 4); + assert(cuda::std::get<2>(v).value == 42); + assert(&ref2 == &cuda::std::get<2>(v)); + auto& ref3 = v.emplace<1>({1}); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<1>(v).size == 1); + assert(&ref3 == &cuda::std::get<1>(v)); +} + +int main(int, char**) { + test_basic(); + test_emplace_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp new file mode 100644 index 0000000000..2b3e97c080 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp @@ -0,0 +1,166 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template T& emplace(Args&&... args); + +#include +// #include +#include +#include + +#include "archetypes.h" +#include "test_convertible.h" +#include "test_macros.h" +#include "variant_test_helpers.h" + +template +__host__ __device__ +constexpr auto test_emplace_exists_imp(int) -> decltype( + cuda::std::declval().template emplace(cuda::std::declval()...), true) { + return true; +} + +template +__host__ __device__ +constexpr auto test_emplace_exists_imp(long) -> bool { + return false; +} + +template __host__ __device__ constexpr bool emplace_exists() { + return test_emplace_exists_imp(0); +} + +__host__ __device__ +void test_emplace_sfinae() { + { + using V = cuda::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 = cuda::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 +} + +__host__ __device__ +void test_basic() { + { + using V = cuda::std::variant; + V v(42); + auto& ref1 = v.emplace(); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<0>(v) == 0); + assert(&ref1 == &cuda::std::get<0>(v)); + auto& ref2 = v.emplace(42); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<0>(v) == 42); + assert(&ref2 == &cuda::std::get<0>(v)); + } + { + using V = + cuda::std::variant; //, cuda::std::string>; + const int x = 100; + V v(cuda::std::in_place_type, -1); + // default emplace a value + auto& ref1 = v.emplace(); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<1>(v) == 0); + assert(&ref1 == &cuda::std::get<1>(v)); + auto& ref2 = v.emplace(&x); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<2>(v) == &x); + assert(&ref2 == &cuda::std::get<2>(v)); + // emplace with multiple args + /* auto& ref3 = v.emplace(3u, 'a'); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get<4>(v) == "aaa"); + assert(&ref3 == &cuda::std::get<4>(v));*/ + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { + using V = cuda::std::variant; //, + // cuda::std::string>; + const int x = 100; + int y = 42; + int z = 43; + V v(cuda::std::in_place_index<0>, -1); + // default emplace a value + auto& ref1 = v.emplace(); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get(v) == 0); + assert(&ref1 == &cuda::std::get(v)); + // emplace a reference + auto& ref2 = v.emplace(x); + static_assert(cuda::std::is_same_v, ""); + assert(&cuda::std::get(v) == &x); + assert(&ref2 == &cuda::std::get(v)); + // emplace an rvalue reference + auto& ref3 = v.emplace(cuda::std::move(y)); + static_assert(cuda::std::is_same_v, ""); + assert(&cuda::std::get(v) == &y); + assert(&ref3 == &cuda::std::get(v)); + // re-emplace a new reference over the active member + auto& ref4 = v.emplace(cuda::std::move(z)); + static_assert(cuda::std::is_same_v, ""); + assert(&cuda::std::get(v) == &z); + assert(&ref4 == &cuda::std::get(v)); + // emplace with multiple args + /* auto& ref5 = v.emplace(3u, 'a'); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get(v) == "aaa"); + assert(&ref5 == &cuda::std::get(v));*/ + } +#endif +} + +int main(int, char**) { + test_basic(); + test_emplace_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp new file mode 100644 index 0000000000..2970899d26 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// template +// T& emplace(initializer_list il,Args&&... args); + +#include +// #include +#include +#include + +#include "archetypes.h" +#include "test_convertible.h" +#include "test_macros.h" + +struct InitList { + cuda::std::size_t size; + __host__ __device__ + constexpr InitList(cuda::std::initializer_list il) : size(il.size()) {} +}; + +struct InitListArg { + cuda::std::size_t size; + int value; + __host__ __device__ + constexpr InitListArg(cuda::std::initializer_list il, int v) + : size(il.size()), value(v) {} +}; + +template +__host__ __device__ +constexpr auto test_emplace_exists_imp(int) -> decltype( + cuda::std::declval().template emplace(cuda::std::declval()...), true) { + return true; +} + +template +__host__ __device__ +constexpr auto test_emplace_exists_imp(long) -> bool { + return false; +} + +template __host__ __device__ constexpr bool emplace_exists() { + return test_emplace_exists_imp(0); +} + +__host__ __device__ +void test_emplace_sfinae() { + using V = + cuda::std::variant; + using IL = cuda::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"); +} + +__host__ __device__ +void test_basic() { + using V = cuda::std::variant; + V v; + auto& ref1 = v.emplace({1, 2, 3}); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get(v).size == 3); + assert(&ref1 == &cuda::std::get(v)); + auto& ref2 = v.emplace({1, 2, 3, 4}, 42); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get(v).size == 4); + assert(cuda::std::get(v).value == 42); + assert(&ref2 == &cuda::std::get(v)); + auto& ref3 = v.emplace({1}); + static_assert(cuda::std::is_same_v, ""); + assert(cuda::std::get(v).size == 1); + assert(&ref3 == &cuda::std::get(v)); +} + +int main(int, char**) { + test_basic(); + test_emplace_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.status/index.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.status/index.pass.cpp new file mode 100644 index 0000000000..656cf98516 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.status/index.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + +// constexpr size_t index() const noexcept; + +#include +// #include +#include +#include + +#include "archetypes.h" +#include "test_macros.h" +#include "variant_test_helpers.h" + + +int main(int, char**) { + { + using V = cuda::std::variant; + constexpr V v; + static_assert(v.index() == 0, ""); + } + { + using V = cuda::std::variant; + V v; + assert(v.index() == 0); + } + { + using V = cuda::std::variant; + constexpr V v(cuda::std::in_place_index<1>); + static_assert(v.index() == 1, ""); + } + /*{ + using V = cuda::std::variant; + V v("abc"); + assert(v.index() == 1); + v = 42; + assert(v.index() == 0); + }*/ +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = cuda::std::variant; + V v; + assert(v.index() == 0); + makeEmpty(v); + assert(v.index() == cuda::std::variant_npos); + } +#endif + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp new file mode 100644 index 0000000000..64347a29fa --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.status/valueless_by_exception.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + +// constexpr bool valueless_by_exception() const noexcept; + +#include +// #include +#include +#include + +#include "archetypes.h" +#include "test_macros.h" +#include "variant_test_helpers.h" + + +int main(int, char**) { + { + using V = cuda::std::variant; + constexpr V v; + static_assert(!v.valueless_by_exception(), ""); + } + { + using V = cuda::std::variant; + V v; + assert(!v.valueless_by_exception()); + } + /*{ + using V = cuda::std::variant; + const V v("abc"); + assert(!v.valueless_by_exception()); + }*/ +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using V = cuda::std::variant; + V v; + assert(!v.valueless_by_exception()); + makeEmpty(v); + assert(v.valueless_by_exception()); + } +#endif + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp new file mode 100644 index 0000000000..fc2fd95d0b --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant.swap/swap.pass.cpp @@ -0,0 +1,605 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template class variant; + +// void swap(variant& rhs) noexcept(see below) + +#include +// #include +#include +#include + +#include "test_convertible.h" +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct NotSwappable {}; +__host__ __device__ +void swap(NotSwappable &, NotSwappable &) = delete; + +struct NotCopyable { + NotCopyable() = default; + NotCopyable(const NotCopyable &) = delete; + NotCopyable &operator=(const NotCopyable &) = delete; +}; + +struct NotCopyableWithSwap { + NotCopyableWithSwap() = default; + NotCopyableWithSwap(const NotCopyableWithSwap &) = delete; + NotCopyableWithSwap &operator=(const NotCopyableWithSwap &) = delete; +}; +__host__ __device__ +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; +}; +__host__ __device__ +void swap(NotMoveAssignableWithSwap &, NotMoveAssignableWithSwap &) noexcept {} + +template __host__ __device__ void do_throw() {} + +template <> __host__ __device__ void do_throw() { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw 42; +#else + _LIBCUDACXX_UNREACHABLE(); +#endif +} + +template +struct NothrowTypeImp { + STATIC_MEMBER_VAR(move_called, int); + STATIC_MEMBER_VAR(move_assign_called, int); + STATIC_MEMBER_VAR(swap_called, int); + __host__ __device__ + static void reset() { move_called() = move_assign_called() = swap_called() = 0; } + NothrowTypeImp() = default; + __host__ __device__ + explicit NothrowTypeImp(int v) : value(v) {} + __host__ __device__ + NothrowTypeImp(const NothrowTypeImp &o) noexcept(NT_Copy) : value(o.value) { + assert(false); + } // never called by test + __host__ __device__ + NothrowTypeImp(NothrowTypeImp &&o) noexcept(NT_Move) : value(o.value) { + ++move_called(); + do_throw(); + o.value = -1; + } + __host__ __device__ + NothrowTypeImp &operator=(const NothrowTypeImp &) noexcept(NT_CopyAssign) { + assert(false); + return *this; + } // never called by the tests + __host__ __device__ + NothrowTypeImp &operator=(NothrowTypeImp &&o) noexcept(NT_MoveAssign) { + ++move_assign_called(); + do_throw(); + value = o.value; + o.value = -1; + return *this; + } + int value; +}; + +template +__host__ __device__ +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_MEMBER_VAR(move_called, int); + __host__ __device__ + static void reset() { move_called() = 0; } + NonThrowingNonNoexceptType() = default; + __host__ __device__ + NonThrowingNonNoexceptType(int v) : value(v) {} + __host__ __device__ + NonThrowingNonNoexceptType(NonThrowingNonNoexceptType &&o) noexcept(false) + : value(o.value) { + ++move_called(); + o.value = -1; + } + __host__ __device__ + NonThrowingNonNoexceptType & + operator=(NonThrowingNonNoexceptType &&) noexcept(false) { + assert(false); // never called by the tests. + return *this; + } + int value; +}; + +struct ThrowsOnSecondMove { + int value; + int move_count; + __host__ __device__ + ThrowsOnSecondMove(int v) : value(v), move_count(0) {} + __host__ __device__ + ThrowsOnSecondMove(ThrowsOnSecondMove &&o) noexcept(false) + : value(o.value), move_count(o.move_count + 1) { + if (move_count == 2) + do_throw(); + o.value = -1; + } + __host__ __device__ + ThrowsOnSecondMove &operator=(ThrowsOnSecondMove &&) { + assert(false); // not called by test + return *this; + } +}; + +__host__ __device__ +void test_swap_valueless_by_exception() { +#ifndef TEST_HAS_NO_EXCEPTIONS + using V = cuda::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(cuda::std::get<0>(v2) == 42); + // swap again + v2.swap(v1); + assert(v2.valueless_by_exception()); + assert(cuda::std::get<0>(v1) == 42); + } + { // non-member swap + swap(v1, v2); + assert(v1.valueless_by_exception()); + assert(cuda::std::get<0>(v2) == 42); + // swap again + swap(v1, v2); + assert(v2.valueless_by_exception()); + assert(cuda::std::get<0>(v1) == 42); + } + } +#endif +} + +__host__ __device__ +void test_swap_same_alternative() { + { + using T = ThrowingTypeWithNothrowSwap; + using V = cuda::std::variant; + T::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::std::in_place_index<0>, 100); + v1.swap(v2); + assert(T::swap_called() == 1); + assert(cuda::std::get<0>(v1).value == 100); + assert(cuda::std::get<0>(v2).value == 42); + swap(v1, v2); + assert(T::swap_called() == 2); + assert(cuda::std::get<0>(v1).value == 42); + assert(cuda::std::get<0>(v2).value == 100); + } + { + using T = NothrowMoveable; + using V = cuda::std::variant; + T::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::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(cuda::std::get<0>(v1).value == 100); + assert(cuda::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(cuda::std::get<0>(v1).value == 42); + assert(cuda::std::get<0>(v2).value == 100); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using T = NothrowTypeWithThrowingSwap; + using V = cuda::std::variant; + T::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::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(cuda::std::get<0>(v1).value == 42); + assert(cuda::std::get<0>(v2).value == 100); + } + { + using T = ThrowingMoveCtor; + using V = cuda::std::variant; + T::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::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(cuda::std::get<0>(v1).value == + 42); // throw happened before v1 was moved from + assert(cuda::std::get<0>(v2).value == 100); + } + { + using T = ThrowingMoveAssignNothrowMoveCtor; + using V = cuda::std::variant; + T::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::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(cuda::std::get<0>(v1).value == -1); // v1 was moved from + assert(cuda::std::get<0>(v2).value == 100); + } +#endif +} + +__host__ __device__ +void test_swap_different_alternatives() { + { + using T = NothrowMoveCtorWithThrowingSwap; + using V = cuda::std::variant; + T::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::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. + LIBCPP_ASSERT(T::move_called() == 1); + assert(T::move_called() <= 2); + assert(T::move_assign_called() == 0); + assert(cuda::std::get<1>(v1) == 100); + assert(cuda::std::get<0>(v2).value == 42); + T::reset(); + swap(v1, v2); + assert(T::swap_called() == 0); + LIBCPP_ASSERT(T::move_called() == 2); + assert(T::move_called() <= 2); + assert(T::move_assign_called() == 0); + assert(cuda::std::get<0>(v1).value == 42); + assert(cuda::std::get<1>(v2) == 100); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + using T1 = ThrowingTypeWithNothrowSwap; + using T2 = NonThrowingNonNoexceptType; + using V = cuda::std::variant; + T1::reset(); + T2::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::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); + // FIXME: libc++ shouldn't move from T2 here. + LIBCPP_ASSERT(T2::move_called() == 1); + assert(T2::move_called <= 1); + assert(cuda::std::get<0>(v1).value == 42); + if (T2::move_called != 0) + assert(v2.valueless_by_exception()); + else + assert(cuda::std::get<1>(v2).value == 100); + } + { + using T1 = NonThrowingNonNoexceptType; + using T2 = ThrowingTypeWithNothrowSwap; + using V = cuda::std::variant; + T1::reset(); + T2::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::std::in_place_index<1>, 100); + try { + v1.swap(v2); + assert(false); + } catch (int) { + } + LIBCPP_ASSERT(T1::move_called() == 0); + assert(T1::move_called <= 1); + assert(T2::swap_called() == 0); + assert(T2::move_called() == 1); // throws + assert(T2::move_assign_called() == 0); + if (T1::move_called != 0) + assert(v1.valueless_by_exception()); + else + assert(cuda::std::get<0>(v1).value == 42); + assert(cuda::std::get<1>(v2).value == 100); + } +// FIXME: The tests below are just very libc++ specific +#ifdef _LIBCUDACXX_VERSION + { + using T1 = ThrowsOnSecondMove; + using T2 = NonThrowingNonNoexceptType; + using V = cuda::std::variant; + T2::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::std::in_place_index<1>, 100); + v1.swap(v2); + assert(T2::move_called() == 2); + assert(cuda::std::get<1>(v1).value == 100); + assert(cuda::std::get<0>(v2).value == 42); + assert(cuda::std::get<0>(v2).move_count == 1); + } + { + using T1 = NonThrowingNonNoexceptType; + using T2 = ThrowsOnSecondMove; + using V = cuda::std::variant; + T1::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::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(cuda::std::get<0>(v2).value == 42); + } +#endif +// testing libc++ extension. If either variant stores a nothrow move +// constructible type v1.swap(v2) provides the strong exception safety +// guarantee. +#ifdef _LIBCUDACXX_VERSION + { + + using T1 = ThrowingTypeWithNothrowSwap; + using T2 = NothrowMoveable; + using V = cuda::std::variant; + T1::reset(); + T2::reset(); + V v1(cuda::std::in_place_index<0>, 42); + V v2(cuda::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(cuda::std::get<0>(v1).value == 42); + assert(cuda::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(cuda::std::get<0>(v1).value == 42); + assert(cuda::std::get<1>(v2).value == 100); + } +#endif // _LIBCUDACXX_VERSION +#endif +} + +template +__host__ __device__ +constexpr auto has_swap_member_imp(int) + -> decltype(cuda::std::declval().swap(cuda::std::declval()), true) { + return true; +} + +template __host__ __device__ constexpr auto has_swap_member_imp(long) -> bool { + return false; +} + +template __host__ __device__ constexpr bool has_swap_member() { + return has_swap_member_imp(0); +} + +__host__ __device__ +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 = cuda::std::variant; + LIBCPP_STATIC_ASSERT(!has_swap_member(), ""); + static_assert(cuda::std::is_swappable_v, ""); + } + { + using V = cuda::std::variant; + LIBCPP_STATIC_ASSERT(!has_swap_member(), ""); + static_assert(!cuda::std::is_swappable_v, ""); + } + { + using V = cuda::std::variant; + LIBCPP_STATIC_ASSERT(!has_swap_member(), ""); + static_assert(!cuda::std::is_swappable_v, ""); + } + { + using V = cuda::std::variant; + LIBCPP_STATIC_ASSERT(!has_swap_member(), ""); + static_assert(!cuda::std::is_swappable_v, ""); + } +} + +__host__ __device__ +void test_swap_noexcept() { + { + using V = cuda::std::variant; + static_assert(cuda::std::is_swappable_v && has_swap_member(), ""); + static_assert(cuda::std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_swappable_v && has_swap_member(), ""); + static_assert(!cuda::std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_swappable_v && has_swap_member(), ""); + static_assert(!cuda::std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_swappable_v && has_swap_member(), ""); + static_assert(!cuda::std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_swappable_v && has_swap_member(), ""); + static_assert(cuda::std::is_nothrow_swappable_v, ""); + // instantiate swap + V v1, v2; + v1.swap(v2); + swap(v1, v2); + } + { + using V = cuda::std::variant; + static_assert(cuda::std::is_swappable_v && has_swap_member(), ""); + static_assert(cuda::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 = cuda::std::variant; + LIBCPP_STATIC_ASSERT(!has_swap_member(), ""); + static_assert(cuda::std::is_swappable_v, ""); + static_assert(cuda::std::is_nothrow_swappable_v, ""); + V v1, v2; + swap(v1, v2); + } +} + +#ifdef _LIBCUDACXX_VERSION +// This is why variant should SFINAE member swap. :-) +template class cuda::std::variant; +#endif + +int main(int, char**) { + test_swap_valueless_by_exception(); + test_swap_same_alternative(); + test_swap_different_alternatives(); + test_swap_sfinae(); + test_swap_noexcept(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_array.fail.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_array.fail.cpp new file mode 100644 index 0000000000..66fd97590b --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_array.fail.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" +#include "test_convertible.h" + +int main(int, char**) +{ + // expected-error-re@variant:* 3 {{{{(static_assert|static assertion)}} failed}} + cuda::std::variant v; // expected-note {{requested here}} + cuda::std::variant v2; // expected-note {{requested here}} + cuda::std::variant v3; // expected-note {{requested here}} + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_empty.fail.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_empty.fail.cpp new file mode 100644 index 0000000000..a4ef64f4e3 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_empty.fail.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +int main(int, char**) +{ + // expected-error-re@variant:* 1 {{{{(static_assert|static assertion)}} failed}} + cuda::std::variant<> v; // expected-note {{requested here}} + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_reference.fail.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_reference.fail.cpp new file mode 100644 index 0000000000..d26f573725 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_reference.fail.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +int main(int, char**) +{ + // expected-error-re@variant:* 3 {{{{(static_assert|static assertion)}} failed}} + cuda::std::variant v; // expected-note {{requested here}} + cuda::std::variant v2; // expected-note {{requested here}} + cuda::std::variant v3; // expected-note {{requested here}} + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_void.fail.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_void.fail.cpp new file mode 100644 index 0000000000..07e01c6cf7 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.variant/variant_void.fail.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// + +// template class variant; + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" +#include "test_convertible.h" + +int main(int, char**) +{ + // expected-error-re@variant:* 3 {{{{(static_assert|static assertion)}} failed}} + cuda::std::variant v; // expected-note {{requested here}} + cuda::std::variant v2; // expected-note {{requested here}} + cuda::std::variant v3; // expected-note {{requested here}} + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp new file mode 100644 index 0000000000..f69417c7d6 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include + +#include "test_macros.h" + +struct Incomplete; +template struct Holder { T t; }; + +struct empty_visitor { + template + __host__ __device__ constexpr void operator()(T)const noexcept {} +}; + +struct holder_visitor { + template + __host__ __device__ constexpr Holder* operator()(T)const noexcept { return nullptr; } +}; + +__host__ __device__ +constexpr bool test(bool do_it) +{ + if (do_it) { + cuda::std::variant*, int> v = nullptr; + cuda::std::visit(empty_visitor{}, v); + cuda::std::visit(holder_visitor{}, v); + cuda::std::visit(empty_visitor{}, v); + cuda::std::visit(holder_visitor{}, v); + } + return true; +} + +int main(int, char**) +{ + test(true); + static_assert(test(true), ""); + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_argument_forwarding.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_argument_forwarding.pass.cpp new file mode 100644 index 0000000000..c4da849e61 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_argument_forwarding.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +__host__ __device__ +void test_argument_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const auto Val = CT_LValue | CT_NonConst; + { // single argument - value type + using V = cuda::std::variant; + V v(42); + const V &cv = v; + cuda::std::visit(obj, v); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cv); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(v)); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(cv)); + assert(Fn::check_call(Val)); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { // single argument - lvalue reference + using V = cuda::std::variant; + int x = 42; + V v(x); + const V &cv = v; + cuda::std::visit(obj, v); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cv); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(v)); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(cv)); + assert(Fn::check_call(Val)); + } + { // single argument - rvalue reference + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + const V &cv = v; + cuda::std::visit(obj, v); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cv); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(v)); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(cv)); + assert(Fn::check_call(Val)); + } +#endif + { // multi argument - multi variant + using V = cuda::std::variant; + V v1(42), v2("hello"), v3(43l); + cuda::std::visit(obj, v1, v2, v3); + assert((Fn::check_call(Val))); + cuda::std::visit(obj, cuda::std::as_const(v1), cuda::std::as_const(v2), cuda::std::move(v3)); + assert((Fn::check_call(Val))); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + cuda::std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + cuda::std::visit(obj, cuda::std::as_const(v1), cuda::std::as_const(v2), cuda::std::move(v3), cuda::std::move(v4)); + assert((Fn::check_call(Val))); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + cuda::std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + cuda::std::visit(obj, cuda::std::as_const(v1), cuda::std::as_const(v2), cuda::std::move(v3), cuda::std::move(v4)); + assert((Fn::check_call(Val))); + } +} + +int main(int, char**) { + test_argument_forwarding(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_call_operator_forwarding.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_call_operator_forwarding.pass.cpp new file mode 100644 index 0000000000..d09604ba7d --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_call_operator_forwarding.pass.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +__host__ __device__ +void test_call_operator_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn &cobj = obj; + { // test call operator forwarding - no variant + cuda::std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + cuda::std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + cuda::std::visit(cuda::std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + cuda::std::visit(cuda::std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); + } + { // test call operator forwarding - single variant, single arg + using V = cuda::std::variant; + V v(42); + cuda::std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + cuda::std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + cuda::std::visit(cuda::std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + cuda::std::visit(cuda::std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + { // test call operator forwarding - single variant, multi arg + using V = cuda::std::variant; + V v(42l); + cuda::std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + cuda::std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + cuda::std::visit(cuda::std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + cuda::std::visit(cuda::std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + { // test call operator forwarding - multi variant, multi arg + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v(42l); + V2 v2("hello"); + cuda::std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + cuda::std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + cuda::std::visit(cuda::std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + cuda::std::visit(cuda::std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + cuda::std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + cuda::std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + cuda::std::visit(cuda::std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + cuda::std::visit(cuda::std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + cuda::std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + cuda::std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + cuda::std::visit(cuda::std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + cuda::std::visit(cuda::std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } +} + +int main(int, char**) { + test_call_operator_forwarding(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_caller_nonconst.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_caller_nonconst.pass.cpp new file mode 100644 index 0000000000..7140c3691f --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_caller_nonconst.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +// See https://llvm.org/PR31916 +__host__ __device__ +void test_caller_accepts_nonconst() { + struct A {}; + struct Visitor { + __host__ __device__ + void operator()(A&) {} + }; + cuda::std::variant v; + cuda::std::visit(Visitor{}, v); +} + +int main(int, char**) { + test_caller_accepts_nonconst(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_constexpr.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_constexpr.pass.cpp new file mode 100644 index 0000000000..0cf6f92d78 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_constexpr.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +__host__ __device__ +void test_constexpr() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + { + using V = cuda::std::variant; + constexpr V v(42); + static_assert(cuda::std::visit(obj, v) == 42, ""); + } + { + using V = cuda::std::variant; + constexpr V v(42l); + static_assert(cuda::std::visit(obj, v) == 42, ""); + } + { + using V1 = cuda::std::variant; + using V2 = cuda::std::variant; + using V3 = cuda::std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert(cuda::std::visit(aobj, v1, v2, v3) == 3, ""); + } + { + using V1 = cuda::std::variant; + using V2 = cuda::std::variant; + using V3 = cuda::std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert(cuda::std::visit(aobj, v1, v2, v3) == 3, ""); + } + { + using V = cuda::std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(cuda::std::visit(aobj, v1, v2, v3, v4) == 4, ""); + } + { + using V = cuda::std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(cuda::std::visit(aobj, v1, v2, v3, v4) == 4, ""); + } +} + +int main(int, char**) { + test_constexpr(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_derived.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_derived.pass.cpp new file mode 100644 index 0000000000..38612ec22a --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_derived.pass.cpp @@ -0,0 +1,129 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +struct MyVariant : cuda::std::variant { + using cuda::std::variant::variant; +}; + +namespace cuda { namespace std { +template +__host__ __device__ +void get(const MyVariant&) { + assert(false); +} +} } // namespace cuda::std + +struct visitor_42 { + template + __host__ __device__ constexpr bool operator()(T x) const noexcept { + assert(x == 42); + return true; + } +}; +struct visitor_142 { + template + __host__ __device__ constexpr bool operator()(T x) const noexcept { + assert(x == 142); + return true; + } +}; +struct visitor_float { + template + __host__ __device__ constexpr bool operator()(T x) const noexcept { + assert(x == -1.25f); + return true; + } +}; +struct visitor_double { + template + __host__ __device__ constexpr bool operator()(T x) const noexcept { + assert(x == 42.3); + return true; + } +}; + +// Check that visit does not take index nor valueless_by_exception members from the base class. +struct EvilVariantBase { + int index{}; + char valueless_by_exception{}; +}; + +struct EvilVariant1 : cuda::std::variant, + cuda::std::tuple, + EvilVariantBase { + using cuda::std::variant::variant; +}; + +// Check that visit unambiguously picks the variant, even if the other base has __impl member. +struct ImplVariantBase { + struct Callable { + __host__ __device__ bool operator()() const { assert(false); return false; } + }; + Callable __impl; +}; + +struct EvilVariant2 : cuda::std::variant, ImplVariantBase { + using cuda::std::variant::variant; +}; + +__host__ __device__ +void test_derived_from_variant() { + auto v1 = MyVariant{42}; + const auto cv1 = MyVariant{142}; + + cuda::std::visit(visitor_42{}, v1); + cuda::std::visit(visitor_142{}, cv1); + cuda::std::visit(visitor_float{}, MyVariant{-1.25f}); + cuda::std::visit(visitor_42{}, cuda::std::move(v1)); + cuda::std::visit(visitor_142{}, cuda::std::move(cv1)); + + cuda::std::visit(visitor_42{}, EvilVariant1{42}); + cuda::std::visit(visitor_double{}, EvilVariant1{42.3}); + + + cuda::std::visit(visitor_42{}, EvilVariant2{42}); + cuda::std::visit(visitor_double{}, EvilVariant2{42.3}); +} + +int main(int, char**) { + test_derived_from_variant(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_exceptions.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_exceptions.pass.cpp new file mode 100644 index 0000000000..2f9f2c59d0 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_exceptions.pass.cpp @@ -0,0 +1,107 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +__host__ __device__ +void test_exceptions() { +#ifndef TEST_HAS_NO_EXCEPTIONS + ReturnArity obj{}; + auto test = [&](auto &&... args) { + try { + cuda::std::visit(obj, args...); + } catch (const cuda::std::bad_variant_access &) { + return true; + } catch (...) { + } + return false; + }; + { + using V = cuda::std::variant; + V v; + makeEmpty(v); + assert(test(v)); + } + { + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v; + makeEmpty(v); + V2 v2("hello"); + assert(test(v, v2)); + } + { + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v; + makeEmpty(v); + V2 v2("hello"); + assert(test(v2, v)); + } + { + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v; + makeEmpty(v); + V2 v2; + makeEmpty(v2); + assert(test(v, v2)); + } + { + using V = cuda::std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + assert(test(v1, v2, v3, v4)); + } + { + using V = cuda::std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + makeEmpty(v2); + makeEmpty(v3); + makeEmpty(v4); + assert(test(v1, v2, v3, v4)); + } +#endif +} + +int main(int, char**) { + test_exceptions(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_return_type.pass.cpp new file mode 100644 index 0000000000..52a45ed11e --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +__host__ __device__ +void test_return_type() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn &cobj = obj; + unused(cobj); + { // test call operator forwarding - no variant + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + } + { // test call operator forwarding - single variant, single arg + using V = cuda::std::variant; + V v(42); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + unused(v); + } + { // test call operator forwarding - single variant, multi arg + using V = cuda::std::variant; + V v(42l); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + unused(v); + } + { // test call operator forwarding - multi variant, multi arg + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v(42l); + V2 v2("hello"); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + unused(v, v2); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + unused(v1, v2, v3, v4); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + unused(v1, v2, v3, v4); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + static_assert(cuda::std::is_same_v, ""); + } +} + +int main(int, char**) { + test_return_type(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_sfinae.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_sfinae.pass.cpp new file mode 100644 index 0000000000..c7bfc09ad4 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit/visit_sfinae.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct any_visitor { + template + __host__ __device__ + void operator()(const T&) const {} +}; + +template (), cuda::std::declval()))> +__host__ __device__ +constexpr bool has_visit(int) { + return true; +} + +template +__host__ __device__ +constexpr bool has_visit(...) { + return false; +} + +__host__ __device__ +void test_sfinae() { + struct BadVariant : cuda::std::variant, cuda::std::variant {}; + struct BadVariant2 : private cuda::std::variant {}; + struct GoodVariant : cuda::std::variant {}; + struct GoodVariant2 : GoodVariant {}; + + static_assert(!has_visit(0), ""); +#if !defined(TEST_COMPILER_MSVC) // MSVC cannot deal with that even with std::variant + static_assert(!has_visit(0), ""); +#endif // !TEST_COMPILER_MSVC + static_assert(!has_visit(0), ""); + static_assert(has_visit>(0), ""); + static_assert(has_visit(0), ""); + static_assert(has_visit(0), ""); +} + +int main(int, char**) { + test_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_argument_forwarding.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_argument_forwarding.pass.cpp new file mode 100644 index 0000000000..08524c6ab3 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_argument_forwarding.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +template +__host__ __device__ +void test_argument_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const auto Val = CT_LValue | CT_NonConst; + { // single argument - value type + using V = cuda::std::variant; + V v(42); + const V &cv = v; + cuda::std::visit(obj, v); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cv); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(v)); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(cv)); + assert(Fn::check_call(Val)); + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { // single argument - lvalue reference + using V = cuda::std::variant; + int x = 42; + V v(x); + const V &cv = v; + cuda::std::visit(obj, v); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cv); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(v)); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(cv)); + assert(Fn::check_call(Val)); + } + { // single argument - rvalue reference + using V = cuda::std::variant; + int x = 42; + V v(cuda::std::move(x)); + const V &cv = v; + cuda::std::visit(obj, v); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cv); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(v)); + assert(Fn::check_call(Val)); + cuda::std::visit(obj, cuda::std::move(cv)); + assert(Fn::check_call(Val)); + } +#endif + { // multi argument - multi variant + using V = cuda::std::variant; + V v1(42), v2("hello"), v3(43l); + cuda::std::visit(obj, v1, v2, v3); + assert((Fn::check_call(Val))); + cuda::std::visit(obj, cuda::std::as_const(v1), cuda::std::as_const(v2), cuda::std::move(v3)); + assert((Fn::check_call(Val))); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + cuda::std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + cuda::std::visit(obj, cuda::std::as_const(v1), cuda::std::as_const(v2), cuda::std::move(v3), cuda::std::move(v4)); + assert((Fn::check_call(Val))); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + cuda::std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + cuda::std::visit(obj, cuda::std::as_const(v1), cuda::std::as_const(v2), cuda::std::move(v3), cuda::std::move(v4)); + assert((Fn::check_call(Val))); + } +} + +int main(int, char**) { + test_argument_forwarding(); + test_argument_forwarding(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_call_operator_forwarding.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_call_operator_forwarding.pass.cpp new file mode 100644 index 0000000000..f844118dae --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_call_operator_forwarding.pass.cpp @@ -0,0 +1,126 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +template +__host__ __device__ +void test_call_operator_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn &cobj = obj; + { // test call operator forwarding - no variant + cuda::std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + cuda::std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + cuda::std::visit(cuda::std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + cuda::std::visit(cuda::std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); + } + { // test call operator forwarding - single variant, single arg + using V = cuda::std::variant; + V v(42); + cuda::std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + cuda::std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + cuda::std::visit(cuda::std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + cuda::std::visit(cuda::std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + { // test call operator forwarding - single variant, multi arg + using V = cuda::std::variant; + V v(42l); + cuda::std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + cuda::std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + cuda::std::visit(cuda::std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + cuda::std::visit(cuda::std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + { // test call operator forwarding - multi variant, multi arg + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v(42l); + V2 v2("hello"); + cuda::std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + cuda::std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + cuda::std::visit(cuda::std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + cuda::std::visit(cuda::std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + cuda::std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + cuda::std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + cuda::std::visit(cuda::std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + cuda::std::visit(cuda::std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + cuda::std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + cuda::std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + cuda::std::visit(cuda::std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + cuda::std::visit(cuda::std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } +} + +int main(int, char**) { + test_call_operator_forwarding(); + test_call_operator_forwarding(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_caller_nonconst.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_caller_nonconst.pass.cpp new file mode 100644 index 0000000000..da9ead5a04 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_caller_nonconst.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +// See https://bugs.llvm.org/show_bug.cgi?id=31916 +struct A {}; +template +struct Visitor { + __host__ __device__ + auto operator()(A&) { + return ReturnType{}; + } +}; +template<> +struct Visitor { + __host__ __device__ + void operator()(A&) {} +}; + +template +__host__ __device__ +void test_caller_accepts_nonconst() { + cuda::std::variant v; + cuda::std::visit(Visitor{}, v); +} + +int main(int, char**) { + test_caller_accepts_nonconst(); + test_caller_accepts_nonconst(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_constexpr.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_constexpr.pass.cpp new file mode 100644 index 0000000000..cdcfc7b531 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_constexpr.pass.cpp @@ -0,0 +1,134 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +__host__ __device__ +void test_constexpr_void() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + { + using V = cuda::std::variant; + constexpr V v(42); + static_assert((cuda::std::visit(obj, v), 42) == 42, ""); + } + { + using V = cuda::std::variant; + constexpr V v(42l); + static_assert((cuda::std::visit(obj, v), 42) == 42, ""); + } + { + using V1 = cuda::std::variant; + using V2 = cuda::std::variant; + using V3 = cuda::std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert((cuda::std::visit(aobj, v1, v2, v3), 3) == 3, ""); + } + { + using V1 = cuda::std::variant; + using V2 = cuda::std::variant; + using V3 = cuda::std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert((cuda::std::visit(aobj, v1, v2, v3), 3) == 3, ""); + } + { + using V = cuda::std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert((cuda::std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); + } + { + using V = cuda::std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert((cuda::std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); + } +} + +__host__ __device__ +void test_constexpr_int() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + { + using V = cuda::std::variant; + constexpr V v(42); + static_assert(cuda::std::visit(obj, v) == 42, ""); + } + { + using V = cuda::std::variant; + constexpr V v(42l); + static_assert(cuda::std::visit(obj, v) == 42, ""); + } + { + using V1 = cuda::std::variant; + using V2 = cuda::std::variant; + using V3 = cuda::std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert(cuda::std::visit(aobj, v1, v2, v3) == 3, ""); + } + { + using V1 = cuda::std::variant; + using V2 = cuda::std::variant; + using V3 = cuda::std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + static_assert(cuda::std::visit(aobj, v1, v2, v3) == 3, ""); + } + { + using V = cuda::std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(cuda::std::visit(aobj, v1, v2, v3, v4) == 4, ""); + } + { + using V = cuda::std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(cuda::std::visit(aobj, v1, v2, v3, v4) == 4, ""); + } +} + +struct visitor_side_effects { + int arg_; + __host__ __device__ constexpr visitor_side_effects(int arg) noexcept : arg_(arg) {} + __host__ __device__ constexpr void operator()(int& x) const noexcept { x = arg_; } +}; +__host__ __device__ constexpr int test_constexpr_explicit_side_effect() { + cuda::std::variant v = 101; + cuda::std::visit(visitor_side_effects{202}, v); + return cuda::std::get(v); +} +static_assert(test_constexpr_explicit_side_effect() == 202, ""); + +int main(int, char**) { + test_constexpr_void(); + test_constexpr_int(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_derived.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_derived.pass.cpp new file mode 100644 index 0000000000..0f19157c6d --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_derived.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct visitor_42 { + template + __host__ __device__ constexpr bool operator()(T x) const noexcept { + assert(x == 42); + return true; + } +}; +struct visitor_42_3 { + template + __host__ __device__ constexpr bool operator()(T x) const noexcept { + assert(x == 42.3); + return true; + } +}; +struct visitor_float { + template + __host__ __device__ constexpr bool operator()(T x) const noexcept { + assert(x == -1.3f); + return true; + } +}; + +struct MyVariant : cuda::std::variant { + using cuda::std::variant::variant; +}; + +// Check that visit does not take index nor valueless_by_exception members from the base class. +struct EvilVariantBase { + int index{}; + char valueless_by_exception{}; +}; + +struct EvilVariant1 : cuda::std::variant, + cuda::std::tuple, + EvilVariantBase { + using cuda::std::variant::variant; +}; + +// Check that visit unambiguously picks the variant, even if the other base has __impl member. +struct ImplVariantBase { + struct Callable { + __host__ __device__ + bool operator()() const { assert(false); return false; } + }; + + Callable __impl; +}; + + struct EvilVariant2 : cuda::std::variant, ImplVariantBase { + using cuda::std::variant::variant; + }; + +__host__ __device__ +void test_derived_from_variant() { + cuda::std::visit(visitor_42{}, MyVariant{42}); + cuda::std::visit(visitor_float{}, MyVariant{-1.3f}); + + cuda::std::visit(visitor_42{}, EvilVariant1{42}); + cuda::std::visit(visitor_42_3{}, EvilVariant1{42.3}); + + cuda::std::visit(visitor_42{}, EvilVariant2{42}); + cuda::std::visit(visitor_42_3{}, EvilVariant2{42.3}); +} + +int main(int, char**) { + test_derived_from_variant(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_exceptions.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_exceptions.pass.cpp new file mode 100644 index 0000000000..71cfe901ab --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_exceptions.pass.cpp @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +template +__host__ __device__ +void test_exceptions() { +#ifndef TEST_HAS_NO_EXCEPTIONS + ReturnArity obj{}; + auto test = [&](auto &&... args) { + try { + cuda::std::visit(obj, args...); + } catch (const cuda::std::bad_variant_access &) { + return true; + } catch (...) { + } + return false; + }; + { + using V = cuda::std::variant; + V v; + makeEmpty(v); + assert(test(v)); + } + { + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v; + makeEmpty(v); + V2 v2("hello"); + assert(test(v, v2)); + } + { + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v; + makeEmpty(v); + V2 v2("hello"); + assert(test(v2, v)); + } + { + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v; + makeEmpty(v); + V2 v2; + makeEmpty(v2); + assert(test(v, v2)); + } + { + using V = cuda::std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + assert(test(v1, v2, v3, v4)); + } + { + using V = cuda::std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + makeEmpty(v2); + makeEmpty(v3); + makeEmpty(v4); + assert(test(v1, v2, v3, v4)); + } +#endif +} + +int main(int, char**) { + test_exceptions(); + test_exceptions(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_return_type.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_return_type.pass.cpp new file mode 100644 index 0000000000..8ece4b0ecd --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_return_type.pass.cpp @@ -0,0 +1,108 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct almost_string { + const char * ptr; + + __host__ __device__ + almost_string(const char * ptr) : ptr(ptr) {} + + __host__ __device__ + friend bool operator==(const almost_string & lhs, const almost_string & rhs) { + return lhs.ptr == rhs.ptr; + } +}; + +template +__host__ __device__ +void test_return_type() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn &cobj = obj; + unused(cobj); + { // test call operator forwarding - no variant + static_assert(cuda::std::is_same_v(obj)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cobj)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(obj))), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(cobj))), ReturnType>, ""); + } + { // test call operator forwarding - single variant, single arg + using V = cuda::std::variant; + V v(42); + static_assert(cuda::std::is_same_v(obj, v)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cobj, v)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(obj), v)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(cobj), v)), ReturnType>, ""); + unused(v); + } + { // test call operator forwarding - single variant, multi arg + using V = cuda::std::variant; + V v(42l); + static_assert(cuda::std::is_same_v(obj, v)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cobj, v)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(obj), v)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(cobj), v)), ReturnType>, ""); + unused(v); + } + { // test call operator forwarding - multi variant, multi arg + using V = cuda::std::variant; + using V2 = cuda::std::variant; + V v(42l); + V2 v2("hello"); + static_assert(cuda::std::is_same_v(obj, v, v2)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cobj, v, v2)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(obj), v, v2)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(cobj), v, v2)), ReturnType>, ""); + unused(v, v2); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(101), v4(1.1); + static_assert(cuda::std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(obj), v1, v2, v3, v4)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(cobj), v1, v2, v3, v4)), ReturnType>, ""); + unused(v1, v2, v3, v4); + } + { + using V = cuda::std::variant; + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + static_assert(cuda::std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(obj), v1, v2, v3, v4)), ReturnType>, ""); + static_assert(cuda::std::is_same_v(cuda::std::move(cobj), v1, v2, v3, v4)), ReturnType>, ""); + unused(v1, v2, v3, v4); + } +} + +int main(int, char**) { + test_return_type(); + test_return_type(); + + return 0; +} diff --git a/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_sfinae.pass.cpp b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_sfinae.pass.cpp new file mode 100644 index 0000000000..6a4301a128 --- /dev/null +++ b/libcudacxx/test/libcudacxx/std/utilities/variant/variant.visit_return/visit_sfinae.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 +// UNSUPPORTED: msvc-19.16 + +// Throwing bad_variant_access is supported starting in macosx10.13 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +// #include +// #include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +struct any_visitor { + template + __host__ __device__ + bool operator()(const T&) { + return true; + } +}; + +template ( + cuda::std::declval(), cuda::std::declval()))> +__host__ __device__ +constexpr bool has_visit(int) { + return true; +} + +template +__host__ __device__ +constexpr bool has_visit(...) { + return false; +} + +__host__ __device__ +void test_sfinae() { + struct BadVariant : cuda::std::variant, cuda::std::variant {}; + + static_assert(has_visit >(int()), ""); +#if !defined(TEST_COMPILER_MSVC) // MSVC cannot deal with that even with std::variant + static_assert(!has_visit(int()), ""); +#endif // !TEST_COMPILER_MSVC +} + +int main(int, char**) { + test_sfinae(); + + return 0; +} diff --git a/libcudacxx/test/smoke/CMakeLists.txt b/libcudacxx/test/smoke/CMakeLists.txt index 5b82c67679..0eed33b061 100644 --- a/libcudacxx/test/smoke/CMakeLists.txt +++ b/libcudacxx/test/smoke/CMakeLists.txt @@ -2,7 +2,7 @@ add_custom_target(libcudacxx.test.smoke) set(cpp_std_versions 11 14 17 20) -set(cpp_11_exclusions "cuda/annotated_ptr" "cuda/std/mdspan") +set(cpp_11_exclusions "cuda/annotated_ptr" "cuda/std/mdspan" "cuda/std/variant") set(cpp_14_exclusions "cuda/annotated_ptr" "cuda/std/mdspan") set(cpp_17_exclusions "cuda/annotated_ptr" "cuda/std/mdspan") set(cpp_20_exclusions "cuda/annotated_ptr") diff --git a/libcudacxx/test/support/test_macros.h b/libcudacxx/test/support/test_macros.h index 82eff26cb0..da8827f6fa 100644 --- a/libcudacxx/test/support/test_macros.h +++ b/libcudacxx/test/support/test_macros.h @@ -401,9 +401,9 @@ inline void DoNotOptimize(Tp const& value) { return v; \ } -template +template __host__ __device__ -constexpr bool unused(T &&) {return true;} +constexpr bool unused(T&&...) {return true;} // Define a helper macro to properly suppress warnings #define _TEST_TOSTRING2(x) #x diff --git a/libcudacxx/test/support/type_id.h b/libcudacxx/test/support/type_id.h index 8ca3f5571c..14753de987 100644 --- a/libcudacxx/test/support/type_id.h +++ b/libcudacxx/test/support/type_id.h @@ -8,15 +8,21 @@ #ifndef SUPPORT_TYPE_ID_H #define SUPPORT_TYPE_ID_H -#include -#include -#include -#include #include +#include #include "test_macros.h" + +#ifndef TEST_COMPILER_NVRTC +#include +#include + #include "demangle.h" +#endif // TEST_COMPILER_NVRTC +#if TEST_STD_VER < 11 +#error This header requires C++11 or greater +#endif // TypeID - Represent a unique identifier for a type. TypeID allows equality // comparisons between different types. @@ -26,13 +32,25 @@ struct TypeID { __host__ __device__ friend bool operator!=(TypeID const& LHS, TypeID const& RHS) {return LHS.m_id != RHS.m_id; } +#if 0 std::string name() const { return demangle(m_id); } +#else + __host__ __device__ + const char * name() const { + return m_id; + } +#endif + __host__ __device__ void dump() const { +#if 0 std::string s = name(); std::printf("TypeID: %s\n", s.c_str()); +#else + printf("TypeID: %s\n", m_id); +#endif } private: @@ -82,14 +100,22 @@ __host__ __device__ inline TypeID const& makeArgumentID() { // two typeid's are expected to be equal #define COMPARE_TYPEID(LHS, RHS) CompareTypeIDVerbose(#LHS, LHS, #RHS, RHS) +__host__ __device__ inline bool CompareTypeIDVerbose(const char* LHSString, TypeID const* LHS, const char* RHSString, TypeID const* RHS) { if (*LHS == *RHS) return true; +#if 0 std::printf("TypeID's not equal:\n"); std::printf("%s: %s\n----------\n%s: %s\n", LHSString, LHS->name().c_str(), RHSString, RHS->name().c_str()); +#else + printf("TypeID's not equal:\n"); + printf("%s: %s\n----------\n%s: %s\n", + LHSString, LHS->name(), + RHSString, RHS->name()); +#endif return false; } diff --git a/libcudacxx/test/support/variant_test_helpers.h b/libcudacxx/test/support/variant_test_helpers.h index c1c6aabb1b..98a55e5246 100644 --- a/libcudacxx/test/support/variant_test_helpers.h +++ b/libcudacxx/test/support/variant_test_helpers.h @@ -6,22 +6,24 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + #ifndef SUPPORT_VARIANT_TEST_HELPERS_H #define SUPPORT_VARIANT_TEST_HELPERS_H -#include -#include +#include +#include #include #include "test_macros.h" +#include "type_id.h" -#if TEST_STD_VER <= 14 -#error This file requires C++17 +#if TEST_STD_VER <= 11 +#error This file requires C++14 #endif // FIXME: Currently the variant tests are disabled using this macro. #define TEST_VARIANT_HAS_NO_REFERENCES -#ifdef _LIBCUDACXX_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT +#ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT # define TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS #endif @@ -69,15 +71,15 @@ struct MakeEmptyT { } ~MakeEmptyT() { --alive; } }; -static_assert(std::is_swappable_v, ""); // required for test +static_assert(cuda::std::is_swappable_v, ""); // required for test int MakeEmptyT::alive = 0; template void makeEmpty(Variant& v) { - Variant v2(std::in_place_type); + Variant v2(cuda::std::in_place_type); try { - v = std::move(v2); + v = cuda::std::move(v2); assert(false); } catch (...) { assert(v.valueless_by_exception()); @@ -85,5 +87,86 @@ void makeEmpty(Variant& v) { } #endif // TEST_HAS_NO_EXCEPTIONS +enum CallType : unsigned { + CT_None, + CT_NonConst = 1, + CT_Const = 2, + CT_LValue = 4, + CT_RValue = 8 +}; + +__host__ __device__ +inline constexpr CallType operator|(CallType LHS, CallType RHS) { + return static_cast(static_cast(LHS) | + static_cast(RHS)); +} + +struct ForwardingCallObject { + + template + __host__ __device__ + ForwardingCallObject& operator()(Args&&...) & { + set_call(CT_NonConst | CT_LValue); + return *this; + } + + template + __host__ __device__ + const ForwardingCallObject& operator()(Args&&...) const & { + set_call(CT_Const | CT_LValue); + return *this; + } + + template + __host__ __device__ + ForwardingCallObject&& operator()(Args&&...) && { + set_call(CT_NonConst | CT_RValue); + return cuda::std::move(*this); + } + + template + __host__ __device__ + const ForwardingCallObject&& operator()(Args&&...) const && { + set_call(CT_Const | CT_RValue); + return cuda::std::move(*this); + } + + template __host__ __device__ static void set_call(CallType type) { + assert(last_call_type() == CT_None); + assert(last_call_args() == nullptr); + last_call_type() = type; + last_call_args() = cuda::std::addressof(makeArgumentID()); + } + + template __host__ __device__ 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; + } + + // To check explicit return type for visit + __host__ __device__ + constexpr operator int() const + { + return 0; + } + + STATIC_MEMBER_VAR(last_call_type, CallType); + STATIC_MEMBER_VAR(last_call_args, const TypeID *); +}; + +struct ReturnFirst { + template __host__ __device__ constexpr int operator()(int f, Args &&...) const { + return f; + } +}; + +struct ReturnArity { + template __host__ __device__ constexpr int operator()(Args &&...) const { + return sizeof...(Args); + } +}; #endif // SUPPORT_VARIANT_TEST_HELPERS_H diff --git a/libcudacxx/test/utils/libcudacxx/test/config.py b/libcudacxx/test/utils/libcudacxx/test/config.py index bd55a9c579..f5cfcc43ed 100644 --- a/libcudacxx/test/utils/libcudacxx/test/config.py +++ b/libcudacxx/test/utils/libcudacxx/test/config.py @@ -665,6 +665,7 @@ def configure_compile_flags(self): if self.cxx.type == 'clang': real_arch_format = '--cuda-gpu-arch=sm_{0}' virt_arch_format = '--cuda-gpu-arch=compute_{0}' + self.cxx.compile_flags += ['-O1'] pre_sm_32 = True pre_sm_60 = True pre_sm_70 = True