diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-06-10 13:44:41 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-06-10 13:44:41 +0000 |
| commit | 74c4bc8d0eddcb4786594f1c6b598094fac43859 (patch) | |
| tree | b52af5df113676d27ce94f2a11b1b73f28e1e0a1 /test/std | |
| parent | 7c5c4ef25000522f341d2edb21344a2fe2b881ad (diff) | |
Notes
Diffstat (limited to 'test/std')
13 files changed, 1178 insertions, 65 deletions
diff --git a/test/std/localization/locale.categories/category.ctype/locale.codecvt.byname/ctor_char.pass.cpp b/test/std/localization/locale.categories/category.ctype/locale.codecvt.byname/ctor_char.pass.cpp index 349577835ec6..24c2f23f0db7 100644 --- a/test/std/localization/locale.categories/category.ctype/locale.codecvt.byname/ctor_char.pass.cpp +++ b/test/std/localization/locale.categories/category.ctype/locale.codecvt.byname/ctor_char.pass.cpp @@ -17,6 +17,8 @@ #include <locale> #include <cassert> +#include "platform_support.h" + typedef std::codecvt_byname<char, char, std::mbstate_t> F; class my_facet @@ -38,12 +40,12 @@ int my_facet::count = 0; int main() { { - std::locale l(std::locale::classic(), new my_facet("en_US")); + std::locale l(std::locale::classic(), new my_facet(LOCALE_en_US)); assert(my_facet::count == 1); } assert(my_facet::count == 0); { - my_facet f("en_US", 1); + my_facet f(LOCALE_en_US, 1); assert(my_facet::count == 1); { std::locale l(std::locale::classic(), &f); @@ -53,12 +55,12 @@ int main() } assert(my_facet::count == 0); { - std::locale l(std::locale::classic(), new my_facet(std::string("en_US"))); + std::locale l(std::locale::classic(), new my_facet(std::string(LOCALE_en_US))); assert(my_facet::count == 1); } assert(my_facet::count == 0); { - my_facet f(std::string("en_US"), 1); + my_facet f(std::string(LOCALE_en_US), 1); assert(my_facet::count == 1); { std::locale l(std::locale::classic(), &f); diff --git a/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter.pass.cpp b/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter.pass.cpp new file mode 100644 index 000000000000..6fdd288e2d6a --- /dev/null +++ b/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <numeric> +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// template<class InputIterator, class OutputIterator, class T> +// OutputIterator exclusive_scan(InputIterator first, InputIterator last, +// OutputIterator result, T init); +// + +#include <numeric> +#include <vector> +#include <cassert> + +#include "test_iterators.h" + +template <class Iter1, class T, class Iter2> +void +test(Iter1 first, Iter1 last, T init, Iter2 rFirst, Iter2 rLast) +{ + std::vector<typename std::iterator_traits<Iter1>::value_type> v; + +// Not in place + std::exclusive_scan(first, last, std::back_inserter(v), init); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); + +// In place + v.clear(); + v.assign(first, last); + std::exclusive_scan(v.begin(), v.end(), v.begin(), init); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); +} + + +template <class Iter> +void +test() +{ + int ia[] = {1, 3, 5, 7, 9}; + const int pRes[] = {0, 1, 4, 9, 16}; + const unsigned sa = sizeof(ia) / sizeof(ia[0]); + static_assert(sa == sizeof(pRes) / sizeof(pRes[0])); // just to be sure + + for (unsigned int i = 0; i < sa; ++i ) + test(Iter(ia), Iter(ia + i), 0, pRes, pRes + i); +} + +int triangle(int n) { return n*(n+1)/2; } + +// Basic sanity +void basic_tests() +{ + { + std::vector<int> v(10); + std::fill(v.begin(), v.end(), 3); + std::exclusive_scan(v.begin(), v.end(), v.begin(), 50); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 50 + (int) i * 3); + } + + { + std::vector<int> v(10); + std::iota(v.begin(), v.end(), 0); + std::exclusive_scan(v.begin(), v.end(), v.begin(), 30); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 30 + triangle(i-1)); + } + + { + std::vector<int> v(10); + std::iota(v.begin(), v.end(), 1); + std::exclusive_scan(v.begin(), v.end(), v.begin(), 40); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 40 + triangle(i)); + } + +} + +int main() +{ + basic_tests(); + +// All the iterator categories + test<input_iterator <const int*> >(); + test<forward_iterator <const int*> >(); + test<bidirectional_iterator<const int*> >(); + test<random_access_iterator<const int*> >(); + test<const int*>(); + test< int*>(); +} diff --git a/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter_init_op.pass.cpp b/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter_init_op.pass.cpp new file mode 100644 index 000000000000..ba1673fe467f --- /dev/null +++ b/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter_init_op.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <numeric> +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// template<class InputIterator, class OutputIterator, class T, class BinaryOperation> +// OutputIterator +// exclusive_scan(InputIterator first, InputIterator last, +// OutputIterator result, +// T init, BinaryOperation binary_op); // C++17 + +#include <numeric> +#include <vector> +#include <cassert> + +#include "test_iterators.h" + +template <class Iter1, class T, class Op, class Iter2> +void +test(Iter1 first, Iter1 last, T init, Op op, Iter2 rFirst, Iter2 rLast) +{ + std::vector<typename std::iterator_traits<Iter1>::value_type> v; + +// Not in place + std::exclusive_scan(first, last, std::back_inserter(v), init, op); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); + +// In place + v.clear(); + v.assign(first, last); + std::exclusive_scan(v.begin(), v.end(), v.begin(), init, op); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); +} + + +template <class Iter> +void +test() +{ + int ia[] = {1, 3, 5, 7, 9}; + const int pRes[] = {0, 1, 4, 9, 16}; + const int mRes[] = {1, 1, 3, 15, 105}; + const unsigned sa = sizeof(ia) / sizeof(ia[0]); + static_assert(sa == sizeof(pRes) / sizeof(pRes[0])); // just to be sure + static_assert(sa == sizeof(mRes) / sizeof(mRes[0])); // just to be sure + + for (unsigned int i = 0; i < sa; ++i ) { + test(Iter(ia), Iter(ia + i), 0, std::plus<>(), pRes, pRes + i); + test(Iter(ia), Iter(ia + i), 1, std::multiplies<>(), mRes, mRes + i); + } +} + +int main() +{ +// All the iterator categories + test<input_iterator <const int*> >(); + test<forward_iterator <const int*> >(); + test<bidirectional_iterator<const int*> >(); + test<random_access_iterator<const int*> >(); + test<const int*>(); + test< int*>(); + +// Make sure that the calculations are done using the init typedef + { + std::vector<unsigned char> v(10); + std::iota(v.begin(), v.end(), 1); + std::vector<int> res; + std::exclusive_scan(v.begin(), v.end(), std::back_inserter(res), 1, std::multiplies<>()); + + assert(res.size() == 10); + int j = 1; + assert(res[0] == 1); + for (size_t i = 1; i < v.size(); ++i) + { + j *= i; + assert(res[i] == j); + } + } +} +
\ No newline at end of file diff --git a/test/std/numerics/numeric.ops/transform.exclusive.scan/transform_exclusive_scan_iter_iter_iter_init_bop_uop.pass.cpp b/test/std/numerics/numeric.ops/transform.exclusive.scan/transform_exclusive_scan_iter_iter_iter_init_bop_uop.pass.cpp new file mode 100644 index 000000000000..3bfb336a03f9 --- /dev/null +++ b/test/std/numerics/numeric.ops/transform.exclusive.scan/transform_exclusive_scan_iter_iter_iter_init_bop_uop.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <numeric> +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// template<class InputIterator, class OutputIterator, class T, +// class BinaryOperation, class UnaryOperation> +// OutputIterator transform_exclusive_scan(InputIterator first, InputIterator last, +// OutputIterator result, T init, +// BinaryOperation binary_op, +// UnaryOperation unary_op); + + +#include <numeric> +#include <vector> +#include <cassert> +#include <iostream> + +#include "test_iterators.h" + +template <class _Tp = void> +struct identity : std::unary_function<_Tp, _Tp> +{ + constexpr const _Tp& operator()(const _Tp& __x) const { return __x;} +}; + +template <> +struct identity<void> +{ + template <class _Tp> + constexpr auto operator()(_Tp&& __x) const + _NOEXCEPT_(noexcept(_VSTD::forward<_Tp>(__x))) + -> decltype (_VSTD::forward<_Tp>(__x)) + { return _VSTD::forward<_Tp>(__x); } +}; + +template <class Iter1, class BOp, class UOp, class T, class Iter2> +void +test(Iter1 first, Iter1 last, BOp bop, UOp uop, T init, Iter2 rFirst, Iter2 rLast) +{ + std::vector<typename std::iterator_traits<Iter1>::value_type> v; +// Test not in-place + std::transform_exclusive_scan(first, last, std::back_inserter(v), init, bop, uop); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); + +// Test in-place + v.clear(); + v.assign(first, last); + std::transform_exclusive_scan(v.begin(), v.end(), v.begin(), init, bop, uop); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); +} + + +template <class Iter> +void +test() +{ + int ia[] = { 1, 3, 5, 7, 9}; + const int pResI0[] = { 0, 1, 4, 9, 16}; // with identity + const int mResI0[] = { 0, 0, 0, 0, 0}; + const int pResN0[] = { 0, -1, -4, -9, -16}; // with negate + const int mResN0[] = { 0, 0, 0, 0, 0}; + const int pResI2[] = { 2, 3, 6, 11, 18}; // with identity + const int mResI2[] = { 2, 2, 6, 30, 210}; + const int pResN2[] = { 2, 1, -2, -7, -14}; // with negate + const int mResN2[] = { 2, -2, 6, -30, 210}; + const unsigned sa = sizeof(ia) / sizeof(ia[0]); + static_assert(sa == sizeof(pResI0) / sizeof(pResI0[0])); // just to be sure + static_assert(sa == sizeof(mResI0) / sizeof(mResI0[0])); // just to be sure + static_assert(sa == sizeof(pResN0) / sizeof(pResN0[0])); // just to be sure + static_assert(sa == sizeof(mResN0) / sizeof(mResN0[0])); // just to be sure + static_assert(sa == sizeof(pResI2) / sizeof(pResI2[0])); // just to be sure + static_assert(sa == sizeof(mResI2) / sizeof(mResI2[0])); // just to be sure + static_assert(sa == sizeof(pResN2) / sizeof(pResN2[0])); // just to be sure + static_assert(sa == sizeof(mResN2) / sizeof(mResN2[0])); // just to be sure + + for (unsigned int i = 0; i < sa; ++i ) { + test(Iter(ia), Iter(ia + i), std::plus<>(), identity<>(), 0, pResI0, pResI0 + i); + test(Iter(ia), Iter(ia + i), std::multiplies<>(), identity<>(), 0, mResI0, mResI0 + i); + test(Iter(ia), Iter(ia + i), std::plus<>(), std::negate<>(), 0, pResN0, pResN0 + i); + test(Iter(ia), Iter(ia + i), std::multiplies<>(), std::negate<>(), 0, mResN0, mResN0 + i); + test(Iter(ia), Iter(ia + i), std::plus<>(), identity<>(), 2, pResI2, pResI2 + i); + test(Iter(ia), Iter(ia + i), std::multiplies<>(), identity<>(), 2, mResI2, mResI2 + i); + test(Iter(ia), Iter(ia + i), std::plus<>(), std::negate<>(), 2, pResN2, pResN2 + i); + test(Iter(ia), Iter(ia + i), std::multiplies<>(), std::negate<>(), 2, mResN2, mResN2 + i); + } +} + +int triangle(int n) { return n*(n+1)/2; } + +// Basic sanity +void basic_tests() +{ + { + std::vector<int> v(10); + std::fill(v.begin(), v.end(), 3); + std::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 50, std::plus<>(), identity<>()); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 50 + (int) i * 3); + } + + { + std::vector<int> v(10); + std::iota(v.begin(), v.end(), 0); + std::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 30, std::plus<>(), identity<>()); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 30 + triangle(i-1)); + } + + { + std::vector<int> v(10); + std::iota(v.begin(), v.end(), 1); + std::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 40, std::plus<>(), identity<>()); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 40 + triangle(i)); + } + +// Make sure that the calculations are done using the init typedef + { + std::vector<unsigned char> v(10); + std::iota(v.begin(), v.end(), 1); + std::vector<int> res; + std::transform_exclusive_scan(v.begin(), v.end(), std::back_inserter(res), 1, std::multiplies<>(), identity<>()); + + assert(res.size() == 10); + int j = 1; + assert(res[0] == 1); + for (size_t i = 1; i < res.size(); ++i) + { + j *= i; + assert(res[i] == j); + } + } +} + +int main() +{ + basic_tests(); + +// All the iterator categories + test<input_iterator <const int*> >(); + test<forward_iterator <const int*> >(); + test<bidirectional_iterator<const int*> >(); + test<random_access_iterator<const int*> >(); + test<const int*>(); + test< int*>(); +} diff --git a/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp b/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp index 4de42fbd0243..48c3a73a06cc 100644 --- a/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp +++ b/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp @@ -16,8 +16,10 @@ // mutex(); #include <mutex> +#include <type_traits> int main() { + static_assert(std::is_nothrow_default_constructible<std::mutex>::value, ""); std::mutex m; } diff --git a/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp b/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp index cee73da849b6..8fcd1860843d 100644 --- a/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp +++ b/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp @@ -48,7 +48,6 @@ int main() assert(X::dtor_called == false); assert(static_cast<bool>(opt) == false); } - assert(X::dtor_called == false); // TRANSITION, Clang/C2 VSO#239997 { optional<X> opt(X{}); X::dtor_called = false; @@ -57,5 +56,4 @@ int main() assert(static_cast<bool>(opt) == false); X::dtor_called = false; } - assert(X::dtor_called == false); // TRANSITION, Clang/C2 VSO#239997 } diff --git a/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp b/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp index c219e9704716..f94dcabde513 100644 --- a/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp +++ b/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp @@ -10,7 +10,7 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 // <optional> -// template <class U> T optional<T>::value_or(U&& v) &&; +// template <class U> constexpr T optional<T>::value_or(U&& v) &&; #include <optional> #include <type_traits> @@ -26,22 +26,22 @@ struct Y { int i_; - Y(int i) : i_(i) {} + constexpr Y(int i) : i_(i) {} }; struct X { int i_; - X(int i) : i_(i) {} - X(X&& x) : i_(x.i_) {x.i_ = 0;} - X(const Y& y) : i_(y.i_) {} - X(Y&& y) : i_(y.i_+1) {} + constexpr X(int i) : i_(i) {} + constexpr X(X&& x) : i_(x.i_) {x.i_ = 0;} + constexpr X(const Y& y) : i_(y.i_) {} + constexpr X(Y&& y) : i_(y.i_+1) {} friend constexpr bool operator==(const X& x, const X& y) {return x.i_ == y.i_;} }; -int main() +constexpr int test() { { optional<X> opt(in_place, 2); @@ -65,4 +65,10 @@ int main() assert(std::move(opt).value_or(Y(3)) == 4); assert(!opt); } + return 0; +} + +int main() +{ + static_assert(test() == 0); } diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp new file mode 100644 index 000000000000..7b9c061b3ae8 --- /dev/null +++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp @@ -0,0 +1,155 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: libcpp-no-deduction-guides + +// GCC's implementation of class template deduction is still immature and runs +// into issues with libc++. However GCC accepts this code when compiling +// against libstdc++. +// XFAIL: gcc + +// <string> + +// Test that the constructors offered by std::basic_string are formulated +// so they're compatible with implicit deduction guides. + +#include <tuple> +#include <memory> +#include <cassert> + +#include "test_macros.h" +#include "archetypes.hpp" + + +// Overloads +// using A = Allocator +// using AT = std::allocator_arg_t +// --------------- +// (1) tuple(const Types&...) -> tuple<Types...> +// (2) explicit tuple(const Types&...) -> tuple<Types...> +// (3) tuple(AT, A const&, Types const&...) -> tuple<Types...> +// (4) explicit tuple(AT, A const&, Types const&...) -> tuple<Types...> +// (5) tuple(tuple const& t) -> decltype(t) +// (6) tuple(tuple&& t) -> decltype(t) +// (7) tuple(AT, A const&, tuple const& t) -> decltype(t) +// (8) tuple(AT, A const&, tuple&& t) -> decltype(t) +void test_primary_template() +{ + const std::allocator<int> A; + const auto AT = std::allocator_arg; + { // Testing (1) + int x = 101; + std::tuple t1(42); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<int>); + std::tuple t2(x, 0.0, nullptr); + ASSERT_SAME_TYPE(decltype(t2), std::tuple<int, double, decltype(nullptr)>); + } + { // Testing (2) + using T = ExplicitTestTypes::TestType; + static_assert(!std::is_convertible<T const&, T>::value, ""); + + std::tuple t1(T{}); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<T>); + + const T v{}; + std::tuple t2(T{}, 101l, v); + ASSERT_SAME_TYPE(decltype(t2), std::tuple<T, long, T>); + } + { // Testing (3) + int x = 101; + std::tuple t1(AT, A, 42); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<int>); + + std::tuple t2(AT, A, 42, 0.0, x); + ASSERT_SAME_TYPE(decltype(t2), std::tuple<int, double, int>); + } + { // Testing (4) + using T = ExplicitTestTypes::TestType; + static_assert(!std::is_convertible<T const&, T>::value, ""); + + std::tuple t1(AT, A, T{}); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<T>); + + const T v{}; + std::tuple t2(AT, A, T{}, 101l, v); + ASSERT_SAME_TYPE(decltype(t2), std::tuple<T, long, T>); + } + { // Testing (5) + using Tup = std::tuple<int, decltype(nullptr)>; + const Tup t(42, nullptr); + + std::tuple t1(t); + ASSERT_SAME_TYPE(decltype(t1), Tup); + } + { // Testing (6) + using Tup = std::tuple<void*, unsigned, char>; + std::tuple t1(Tup(nullptr, 42, 'a')); + ASSERT_SAME_TYPE(decltype(t1), Tup); + } + { // Testing (7) + using Tup = std::tuple<int, decltype(nullptr)>; + const Tup t(42, nullptr); + + std::tuple t1(AT, A, t); + ASSERT_SAME_TYPE(decltype(t1), Tup); + } + { // Testing (8) + using Tup = std::tuple<void*, unsigned, char>; + std::tuple t1(AT, A, Tup(nullptr, 42, 'a')); + ASSERT_SAME_TYPE(decltype(t1), Tup); + } +} + +// Overloads +// using A = Allocator +// using AT = std::allocator_arg_t +// --------------- +// (1) tuple() -> tuple<> +// (2) tuple(AT, A const&) -> tuple<> +// (3) tuple(tuple const&) -> tuple<> +// (4) tuple(tuple&&) -> tuple<> +// (5) tuple(AT, A const&, tuple const&) -> tuple<> +// (6) tuple(AT, A const&, tuple&&) -> tuple<> +void test_empty_specialization() +{ + std::allocator<int> A; + const auto AT = std::allocator_arg; + { // Testing (1) + std::tuple t1{}; + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (2) + std::tuple t1{AT, A}; + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (3) + const std::tuple<> t{}; + std::tuple t1(t); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (4) + std::tuple t1(std::tuple<>{}); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (5) + const std::tuple<> t{}; + std::tuple t1(AT, A, t); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (6) + std::tuple t1(AT, A, std::tuple<>{}); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } +} + +int main() { + test_primary_template(); + test_empty_specialization(); +} diff --git a/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp b/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp index dd5880ea6635..29228e562d69 100644 --- a/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -68,6 +68,28 @@ struct ThrowsCtorT { } }; +struct MoveCrashes { + int value; + MoveCrashes(int v = 0) noexcept : value{v} {} + MoveCrashes(MoveCrashes &&) noexcept { assert(false); } + MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; } + MoveCrashes &operator=(int v) noexcept { + value = v; + return *this; + } +}; + +struct ThrowsCtorTandMove { + int value; + ThrowsCtorTandMove() : value(0) {} + ThrowsCtorTandMove(int) noexcept(false) { throw 42; } + ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); } + ThrowsCtorTandMove &operator=(int v) noexcept { + value = v; + return *this; + } +}; + struct ThrowsAssignT { int value; ThrowsAssignT() : value(0) {} @@ -126,7 +148,7 @@ void test_T_assignment_sfinae() { using V = std::variant<int, const int &>; static_assert(!std::is_assignable<V, int>::value, "ambiguous"); } -#endif +#endif // TEST_VARIANT_HAS_NO_REFERENCES } void test_T_assignment_basic() { @@ -163,7 +185,7 @@ void test_T_assignment_basic() { assert(v.index() == 2); assert(std::get<2>(v) == 42); } -#endif +#endif // TEST_VARIANT_HAS_NO_REFERENCES } void test_T_assignment_performs_construction() { @@ -174,9 +196,11 @@ void test_T_assignment_performs_construction() { V v(std::in_place_type<std::string>, "hello"); try { v = 42; + assert(false); } catch (...) { /* ... */ } - assert(v.valueless_by_exception()); + assert(v.index() == 0); + assert(std::get<0>(v) == "hello"); } { using V = std::variant<ThrowsAssignT, std::string>; @@ -185,7 +209,7 @@ void test_T_assignment_performs_construction() { assert(v.index() == 0); assert(std::get<0>(v).value == 42); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_T_assignment_performs_assignment() { @@ -227,7 +251,7 @@ void test_T_assignment_performs_assignment() { assert(v.index() == 1); assert(std::get<1>(v).value == 100); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } int main() { diff --git a/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp b/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp index 4f0009d9d620..068b9a201566 100644 --- a/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp @@ -10,6 +10,10 @@ // 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: with_system_cxx_lib=macosx10.12 // XFAIL: with_system_cxx_lib=macosx10.11 // XFAIL: with_system_cxx_lib=macosx10.10 @@ -35,11 +39,6 @@ struct NoCopy { NoCopy &operator=(const NoCopy &) = default; }; -struct NothrowCopy { - NothrowCopy(const NothrowCopy &) noexcept = default; - NothrowCopy &operator=(const NothrowCopy &) noexcept = default; -}; - struct CopyOnly { CopyOnly(const CopyOnly &) = default; CopyOnly(CopyOnly &&) = delete; @@ -73,7 +72,7 @@ struct CopyAssign { ++alive; ++copy_construct; } - CopyAssign(CopyAssign &&o) : value(o.value) { + CopyAssign(CopyAssign &&o) noexcept : value(o.value) { o.value = -1; ++alive; ++move_construct; @@ -83,7 +82,7 @@ struct CopyAssign { ++copy_assign; return *this; } - CopyAssign &operator=(CopyAssign &&o) { + CopyAssign &operator=(CopyAssign &&o) noexcept { value = o.value; o.value = -1; ++move_assign; @@ -108,6 +107,48 @@ struct CopyDoesThrow { CopyDoesThrow &operator=(const CopyDoesThrow &) noexcept(false); }; + +struct NTCopyAssign { + constexpr NTCopyAssign(int v) : value(v) {} + NTCopyAssign(const NTCopyAssign &) = default; + NTCopyAssign(NTCopyAssign &&) = default; + NTCopyAssign &operator=(const NTCopyAssign &that) { + value = that.value; + return *this; + }; + NTCopyAssign &operator=(NTCopyAssign &&) = delete; + int value; +}; + +static_assert(!std::is_trivially_copy_assignable<NTCopyAssign>::value, ""); +static_assert(std::is_copy_assignable<NTCopyAssign>::value, ""); + +struct TCopyAssign { + 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(std::is_trivially_copy_assignable<TCopyAssign>::value, ""); + +struct TCopyAssignNTMoveAssign { + constexpr TCopyAssignNTMoveAssign(int v) : value(v) {} + TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign &) = default; + TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign &&) = default; + TCopyAssignNTMoveAssign &operator=(const TCopyAssignNTMoveAssign &) = default; + TCopyAssignNTMoveAssign &operator=(TCopyAssignNTMoveAssign &&that) { + value = that.value; + that.value = -1; + return *this; + } + int value; +}; + +static_assert(std::is_trivially_copy_assignable_v<TCopyAssignNTMoveAssign>, ""); + #ifndef TEST_HAS_NO_EXCEPTIONS struct CopyThrows { CopyThrows() = default; @@ -115,6 +156,17 @@ struct CopyThrows { CopyThrows &operator=(const CopyThrows &) { throw 42; } }; +struct CopyCannotThrow { + static int alive; + CopyCannotThrow() { ++alive; } + CopyCannotThrow(const CopyCannotThrow &) noexcept { ++alive; } + CopyCannotThrow(CopyCannotThrow &&) noexcept { assert(false); } + CopyCannotThrow &operator=(const CopyCannotThrow &) noexcept = default; + CopyCannotThrow &operator=(CopyCannotThrow &&) noexcept { assert(false); return *this; } +}; + +int CopyCannotThrow::alive = 0; + struct MoveThrows { static int alive; MoveThrows() { ++alive; } @@ -146,7 +198,7 @@ int MakeEmptyT::alive = 0; template <class Variant> void makeEmpty(Variant &v) { Variant v2(std::in_place_type<MakeEmptyT>); try { - v = v2; + v = std::move(v2); assert(false); } catch (...) { assert(v.valueless_by_exception()); @@ -171,10 +223,8 @@ void test_copy_assignment_sfinae() { static_assert(std::is_copy_assignable<V>::value, ""); } { - // variant only provides copy assignment when both the copy and move - // constructors are well formed using V = std::variant<int, CopyOnly>; - static_assert(!std::is_copy_assignable<V>::value, ""); + static_assert(std::is_copy_assignable<V>::value, ""); } { using V = std::variant<int, NoCopy>; @@ -188,6 +238,29 @@ void test_copy_assignment_sfinae() { using V = std::variant<int, MoveOnlyNT>; static_assert(!std::is_copy_assignable<V>::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant<int, long>; + static_assert(std::is_trivially_copy_assignable<V>::value, ""); + } + { + using V = std::variant<int, NTCopyAssign>; + static_assert(!std::is_trivially_copy_assignable<V>::value, ""); + static_assert(std::is_copy_assignable<V>::value, ""); + } + { + using V = std::variant<int, TCopyAssign>; + static_assert(std::is_trivially_copy_assignable<V>::value, ""); + } + { + using V = std::variant<int, TCopyAssignNTMoveAssign>; + static_assert(std::is_trivially_copy_assignable<V>::value, ""); + } + { + using V = std::variant<int, CopyOnly>; + static_assert(std::is_trivially_copy_assignable<V>::value, ""); + } } void test_copy_assignment_empty_empty() { @@ -204,7 +277,7 @@ void test_copy_assignment_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_copy_assignment_non_empty_empty() { @@ -230,7 +303,7 @@ void test_copy_assignment_non_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_copy_assignment_empty_non_empty() { @@ -256,9 +329,11 @@ void test_copy_assignment_empty_non_empty() { assert(v1.index() == 2); assert(std::get<2>(v1) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } +template <typename T> struct Result { size_t index; T value; }; + void test_copy_assignment_same_index() { { using V = std::variant<int>; @@ -306,7 +381,65 @@ void test_copy_assignment_same_index() { assert(v1.index() == 1); assert(&std::get<1>(v1) == &mref); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result<int> operator()() const { + using V = std::variant<int>; + V v(43); + V v2(42); + v = v2; + return {v.index(), std::get<0>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result<long> operator()() const { + using V = std::variant<int, long, unsigned>; + V v(43l); + V v2(42l); + v = v2; + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result<int> operator()() const { + using V = std::variant<int, TCopyAssign, unsigned>; + V v(std::in_place_type<TCopyAssign>, 43); + V v2(std::in_place_type<TCopyAssign>, 42); + v = v2; + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result<int> operator()() const { + using V = std::variant<int, TCopyAssignNTMoveAssign, unsigned>; + V v(std::in_place_type<TCopyAssignNTMoveAssign>, 43); + V v2(std::in_place_type<TCopyAssignNTMoveAssign>, 42); + v = v2; + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } } void test_copy_assignment_different_index() { @@ -338,8 +471,6 @@ void test_copy_assignment_different_index() { } #ifndef TEST_HAS_NO_EXCEPTIONS { - // Test that if copy construction throws then original value is - // unchanged. using V = std::variant<int, CopyThrows, std::string>; V v1(std::in_place_type<std::string>, "hello"); V v2(std::in_place_type<CopyThrows>); @@ -348,24 +479,31 @@ void test_copy_assignment_different_index() { assert(false); } catch (...) { /* ... */ } - assert(v1.index() == 2); - assert(std::get<2>(v1) == "hello"); + // 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()); } { - // Test that if move construction throws then the variant is left - // valueless by exception. using V = std::variant<int, MoveThrows, std::string>; V v1(std::in_place_type<std::string>, "hello"); V v2(std::in_place_type<MoveThrows>); assert(MoveThrows::alive == 1); - try { - v1 = v2; - assert(false); - } catch (...) { /* ... */ - } - assert(v1.valueless_by_exception()); + // 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 == 1); + assert(MoveThrows::alive == 2); + } + { + // Test that direct copy construction is preferred when it cannot throw. + using V = std::variant<int, CopyCannotThrow, std::string>; + V v1(std::in_place_type<std::string>, "hello"); + V v2(std::in_place_type<CopyCannotThrow>); + assert(CopyCannotThrow::alive == 1); + v1 = v2; + assert(v1.index() == 1); + assert(v2.index() == 1); + assert(CopyCannotThrow::alive == 2); } { using V = std::variant<int, CopyThrows, std::string>; @@ -389,9 +527,60 @@ void test_copy_assignment_different_index() { assert(v2.index() == 2); assert(std::get<2>(v2) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result<long> operator()() const { + using V = std::variant<int, long, unsigned>; + V v(43); + V v2(42l); + v = v2; + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result<int> operator()() const { + using V = std::variant<int, TCopyAssign, unsigned>; + V v(std::in_place_type<unsigned>, 43); + V v2(std::in_place_type<TCopyAssign>, 42); + v = v2; + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } +} + +template <size_t NewIdx, class ValueType> +constexpr bool test_constexpr_assign_extension_imp( + std::variant<long, void*, int>&& v, ValueType&& new_value) +{ + const std::variant<long, void*, int> cp( + std::forward<ValueType>(new_value)); + v = cp; + return v.index() == NewIdx && + std::get<NewIdx>(v) == std::get<NewIdx>(cp); } +void test_constexpr_copy_assignment_extension() { + // The following tests are for not-yet-standardized behavior (P0602): + using V = std::variant<long, void*, int>; + static_assert(std::is_trivially_copyable<V>::value, ""); + static_assert(std::is_trivially_copy_assignable<V>::value, ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); +} int main() { test_copy_assignment_empty_empty(); @@ -401,4 +590,5 @@ int main() { test_copy_assignment_different_index(); test_copy_assignment_sfinae(); test_copy_assignment_not_noexcept(); + test_constexpr_copy_assignment_extension(); } diff --git a/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp b/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp index c1ba87be76d1..c410b4b8f3ef 100644 --- a/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp @@ -10,6 +10,10 @@ // 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: with_system_cxx_lib=macosx10.12 // XFAIL: with_system_cxx_lib=macosx10.11 // XFAIL: with_system_cxx_lib=macosx10.10 @@ -91,6 +95,60 @@ struct MoveAssign { int MoveAssign::move_construct = 0; int MoveAssign::move_assign = 0; +struct NTMoveAssign { + constexpr NTMoveAssign(int v) : value(v) {} + NTMoveAssign(const NTMoveAssign &) = default; + NTMoveAssign(NTMoveAssign &&) = default; + NTMoveAssign &operator=(const NTMoveAssign &that) = default; + NTMoveAssign &operator=(NTMoveAssign &&that) { + value = that.value; + that.value = -1; + return *this; + }; + int value; +}; + +static_assert(!std::is_trivially_move_assignable<NTMoveAssign>::value, ""); +static_assert(std::is_move_assignable<NTMoveAssign>::value, ""); + +struct TMoveAssign { + 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(std::is_trivially_move_assignable<TMoveAssign>::value, ""); + +struct TMoveAssignNTCopyAssign { + constexpr TMoveAssignNTCopyAssign(int v) : value(v) {} + TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default; + TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default; + TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) { + value = that.value; + return *this; + } + TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default; + int value; +}; + +static_assert(std::is_trivially_move_assignable_v<TMoveAssignNTCopyAssign>, ""); + +struct TrivialCopyNontrivialMove { + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default; + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {} + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default; + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept { + return *this; + } +}; + +static_assert(std::is_trivially_copy_assignable_v<TrivialCopyNontrivialMove>, ""); +static_assert(!std::is_trivially_move_assignable_v<TrivialCopyNontrivialMove>, ""); + + void test_move_assignment_noexcept() { { using V = std::variant<int>; @@ -124,10 +182,8 @@ void test_move_assignment_sfinae() { static_assert(std::is_move_assignable<V>::value, ""); } { - // variant only provides move assignment when both the move constructor - // and move assignment operator are well formed. using V = std::variant<int, CopyOnly>; - static_assert(!std::is_move_assignable<V>::value, ""); + static_assert(std::is_move_assignable<V>::value, ""); } { using V = std::variant<int, NoCopy>; @@ -147,6 +203,33 @@ void test_move_assignment_sfinae() { using V = std::variant<int, MoveAssignOnly>; static_assert(!std::is_move_assignable<V>::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant<int, long>; + static_assert(std::is_trivially_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, NTMoveAssign>; + static_assert(!std::is_trivially_move_assignable<V>::value, ""); + static_assert(std::is_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, TMoveAssign>; + static_assert(std::is_trivially_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, TMoveAssignNTCopyAssign>; + static_assert(std::is_trivially_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, TrivialCopyNontrivialMove>; + static_assert(!std::is_trivially_move_assignable<V>::value, ""); + } + { + using V = std::variant<int, CopyOnly>; + static_assert(std::is_trivially_move_assignable<V>::value, ""); + } } void test_move_assignment_empty_empty() { @@ -163,7 +246,7 @@ void test_move_assignment_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_move_assignment_non_empty_empty() { @@ -189,7 +272,7 @@ void test_move_assignment_non_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_move_assignment_empty_non_empty() { @@ -215,9 +298,11 @@ void test_move_assignment_empty_non_empty() { assert(v1.index() == 2); assert(std::get<2>(v1) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } +template <typename T> struct Result { size_t index; T value; }; + void test_move_assignment_same_index() { { using V = std::variant<int>; @@ -264,7 +349,51 @@ void test_move_assignment_same_index() { assert(v1.index() == 1); assert(&std::get<1>(v1) == &mref); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result<int> operator()() const { + using V = std::variant<int>; + V v(43); + V v2(42); + v = std::move(v2); + return {v.index(), std::get<0>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result<long> operator()() const { + using V = std::variant<int, long, unsigned>; + V v(43l); + V v2(42l); + v = std::move(v2); + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result<int> operator()() const { + using V = std::variant<int, TMoveAssign, unsigned>; + V v(std::in_place_type<TMoveAssign>, 43); + V v2(std::in_place_type<TMoveAssign>, 42); + v = std::move(v2); + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } } void test_move_assignment_different_index() { @@ -312,7 +441,60 @@ void test_move_assignment_different_index() { assert(v1.index() == 2); assert(std::get<2>(v1) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result<long> operator()() const { + using V = std::variant<int, long, unsigned>; + V v(43); + V v2(42l); + v = std::move(v2); + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result<long> operator()() const { + using V = std::variant<int, TMoveAssign, unsigned>; + V v(std::in_place_type<unsigned>, 43); + V v2(std::in_place_type<TMoveAssign>, 42); + v = std::move(v2); + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } +} + +template <size_t NewIdx, class ValueType> +constexpr bool test_constexpr_assign_extension_imp( + std::variant<long, void*, int>&& v, ValueType&& new_value) +{ + std::variant<long, void*, int> v2( + std::forward<ValueType>(new_value)); + const auto cp = v2; + v = std::move(v2); + return v.index() == NewIdx && + std::get<NewIdx>(v) == std::get<NewIdx>(cp); +} + +void test_constexpr_move_assignment_extension() { + // The following tests are for not-yet-standardized behavior (P0602): + using V = std::variant<long, void*, int>; + static_assert(std::is_trivially_copyable<V>::value, ""); + static_assert(std::is_trivially_move_assignable<V>::value, ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); } int main() { @@ -323,4 +505,5 @@ int main() { test_move_assignment_different_index(); test_move_assignment_sfinae(); test_move_assignment_noexcept(); + test_constexpr_move_assignment_extension(); } diff --git a/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp b/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp index 3b20c369c638..f3113435f3ce 100644 --- a/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -51,6 +51,34 @@ struct MoveOnlyNT { MoveOnlyNT(MoveOnlyNT &&) {} }; +struct NTCopy { + constexpr NTCopy(int v) : value(v) {} + NTCopy(const NTCopy &that) : value(that.value) {} + NTCopy(NTCopy &&) = delete; + int value; +}; + +static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, ""); +static_assert(std::is_copy_constructible<NTCopy>::value, ""); + +struct TCopy { + constexpr TCopy(int v) : value(v) {} + TCopy(TCopy const &) = default; + TCopy(TCopy &&) = delete; + int value; +}; + +static_assert(std::is_trivially_copy_constructible<TCopy>::value, ""); + +struct TCopyNTMove { + constexpr TCopyNTMove(int v) : value(v) {} + TCopyNTMove(const TCopyNTMove&) = default; + TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; } + int value; +}; + +static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, ""); + #ifndef TEST_HAS_NO_EXCEPTIONS struct MakeEmptyT { static int alive; @@ -71,7 +99,7 @@ int MakeEmptyT::alive = 0; template <class Variant> void makeEmpty(Variant &v) { Variant v2(std::in_place_type<MakeEmptyT>); try { - v = v2; + v = std::move(v2); assert(false); } catch (...) { assert(v.valueless_by_exception()); @@ -96,6 +124,25 @@ void test_copy_ctor_sfinae() { using V = std::variant<int, MoveOnlyNT>; static_assert(!std::is_copy_constructible<V>::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant<int, long>; + static_assert(std::is_trivially_copy_constructible<V>::value, ""); + } + { + using V = std::variant<int, NTCopy>; + static_assert(!std::is_trivially_copy_constructible<V>::value, ""); + static_assert(std::is_copy_constructible<V>::value, ""); + } + { + using V = std::variant<int, TCopy>; + static_assert(std::is_trivially_copy_constructible<V>::value, ""); + } + { + using V = std::variant<int, TCopyNTMove>; + static_assert(std::is_trivially_copy_constructible<V>::value, ""); + } } void test_copy_ctor_basic() { @@ -125,6 +172,50 @@ void test_copy_ctor_basic() { assert(v2.index() == 1); assert(std::get<1>(v2).value == 42); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + constexpr std::variant<int> v(std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr std::variant<int> v2 = v; + static_assert(v2.index() == 0, ""); + static_assert(std::get<0>(v2) == 42, ""); + } + { + constexpr std::variant<int, long> v(std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr std::variant<int, long> v2 = v; + static_assert(v2.index() == 1, ""); + static_assert(std::get<1>(v2) == 42, ""); + } + { + constexpr std::variant<TCopy> v(std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr std::variant<TCopy> v2(v); + static_assert(v2.index() == 0, ""); + static_assert(std::get<0>(v2).value == 42, ""); + } + { + constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr std::variant<int, TCopy> v2(v); + static_assert(v2.index() == 1, ""); + static_assert(std::get<1>(v2).value == 42, ""); + } + { + constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr std::variant<TCopyNTMove> v2(v); + static_assert(v2.index() == 0, ""); + static_assert(std::get<0>(v2).value == 42, ""); + } + { + constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr std::variant<int, TCopyNTMove> v2(v); + static_assert(v2.index() == 1, ""); + static_assert(std::get<1>(v2).value == 42, ""); + } } void test_copy_ctor_valueless_by_exception() { @@ -135,7 +226,7 @@ void test_copy_ctor_valueless_by_exception() { const V &cv1 = v1; V v(cv1); assert(v.valueless_by_exception()); -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } template <size_t Idx> @@ -149,7 +240,7 @@ constexpr bool test_constexpr_copy_ctor_extension_imp( } void test_constexpr_copy_ctor_extension() { - // NOTE: This test is for not yet standardized behavior. + // NOTE: This test is for not yet standardized behavior. (P0602) using V = std::variant<long, void*, const int>; #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible<V>::value, ""); @@ -157,9 +248,9 @@ void test_constexpr_copy_ctor_extension() { static_assert(std::is_trivially_move_constructible<V>::value, ""); static_assert(!std::is_copy_assignable<V>::value, ""); static_assert(!std::is_move_assignable<V>::value, ""); -#else +#else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable<V>::value, ""); -#endif +#endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), ""); static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), ""); static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), ""); diff --git a/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp b/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp index a5de1f77334e..6b392068d5a9 100644 --- a/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp @@ -53,6 +53,34 @@ struct MoveOnlyNT { MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; } }; +struct NTMove { + constexpr NTMove(int v) : value(v) {} + NTMove(const NTMove &) = delete; + NTMove(NTMove &&that) : value(that.value) { that.value = -1; } + int value; +}; + +static_assert(!std::is_trivially_move_constructible<NTMove>::value, ""); +static_assert(std::is_move_constructible<NTMove>::value, ""); + +struct TMove { + constexpr TMove(int v) : value(v) {} + TMove(const TMove &) = delete; + TMove(TMove &&) = default; + int value; +}; + +static_assert(std::is_trivially_move_constructible<TMove>::value, ""); + +struct TMoveNTCopy { + constexpr TMoveNTCopy(int v) : value(v) {} + TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {} + TMoveNTCopy(TMoveNTCopy&&) = default; + int value; +}; + +static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, ""); + #ifndef TEST_HAS_NO_EXCEPTIONS struct MakeEmptyT { static int alive; @@ -73,7 +101,7 @@ int MakeEmptyT::alive = 0; template <class Variant> void makeEmpty(Variant &v) { Variant v2(std::in_place_type<MakeEmptyT>); try { - v = v2; + v = std::move(v2); assert(false); } catch (...) { assert(v.valueless_by_exception()); @@ -117,8 +145,30 @@ void test_move_ctor_sfinae() { using V = std::variant<int, NoCopy>; static_assert(!std::is_move_constructible<V>::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant<int, long>; + static_assert(std::is_trivially_move_constructible<V>::value, ""); + } + { + using V = std::variant<int, NTMove>; + static_assert(!std::is_trivially_move_constructible<V>::value, ""); + static_assert(std::is_move_constructible<V>::value, ""); + } + { + using V = std::variant<int, TMove>; + static_assert(std::is_trivially_move_constructible<V>::value, ""); + } + { + using V = std::variant<int, TMoveNTCopy>; + static_assert(std::is_trivially_move_constructible<V>::value, ""); + } } +template <typename T> +struct Result { size_t index; T value; }; + void test_move_ctor_basic() { { std::variant<int> v(std::in_place_index<0>, 42); @@ -162,6 +212,80 @@ void test_move_ctor_basic() { assert(std::get<1>(v).value == -1); assert(std::get<1>(v2).value == 42); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result<int> operator()() const { + std::variant<int> v(std::in_place_index<0>, 42); + std::variant<int> v2 = std::move(v); + return {v2.index(), std::get<0>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result<long> operator()() const { + std::variant<int, long> v(std::in_place_index<1>, 42); + std::variant<int, long> v2 = std::move(v); + return {v2.index(), std::get<1>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result<TMove> operator()() const { + std::variant<TMove> v(std::in_place_index<0>, 42); + std::variant<TMove> v2(std::move(v)); + return {v2.index(), std::get<0>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + constexpr Result<TMove> operator()() const { + std::variant<int, TMove> v(std::in_place_index<1>, 42); + std::variant<int, TMove> v2(std::move(v)); + return {v2.index(), std::get<1>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + constexpr Result<TMoveNTCopy> operator()() const { + std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42); + std::variant<TMoveNTCopy> v2(std::move(v)); + return {v2.index(), std::get<0>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + constexpr Result<TMoveNTCopy> operator()() const { + std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42); + std::variant<int, TMoveNTCopy> v2(std::move(v)); + return {v2.index(), std::get<1>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value.value == 42, ""); + } } void test_move_ctor_valueless_by_exception() { @@ -171,7 +295,7 @@ void test_move_ctor_valueless_by_exception() { makeEmpty(v1); V v(std::move(v1)); assert(v.valueless_by_exception()); -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } template <size_t Idx> @@ -186,7 +310,7 @@ constexpr bool test_constexpr_ctor_extension_imp( } void test_constexpr_move_ctor_extension() { - // NOTE: This test is for not yet standardized behavior. + // NOTE: This test is for not yet standardized behavior. (P0602) using V = std::variant<long, void*, const int>; #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible<V>::value, ""); @@ -194,9 +318,9 @@ void test_constexpr_move_ctor_extension() { static_assert(std::is_trivially_move_constructible<V>::value, ""); static_assert(!std::is_copy_assignable<V>::value, ""); static_assert(!std::is_move_assignable<V>::value, ""); -#else +#else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable<V>::value, ""); -#endif +#endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_move_constructible<V>::value, ""); static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), ""); static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), ""); |
