// { dg-options "-std=gnu++17" } // { dg-do compile } // Copyright (C) 2016-2019 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING3. If not see // . #include #include #include using namespace std; struct AllDeleted { AllDeleted() = delete; AllDeleted(const AllDeleted&) = delete; AllDeleted(AllDeleted&&) = delete; AllDeleted& operator=(const AllDeleted&) = delete; AllDeleted& operator=(AllDeleted&&) = delete; }; struct Empty { Empty() { }; Empty(const Empty&) { }; Empty(Empty&&) { }; Empty& operator=(const Empty&) { return *this; }; Empty& operator=(Empty&&) { return *this; }; }; struct DefaultNoexcept { DefaultNoexcept() noexcept = default; DefaultNoexcept(const DefaultNoexcept&) noexcept = default; DefaultNoexcept(DefaultNoexcept&&) noexcept = default; DefaultNoexcept& operator=(const DefaultNoexcept&) noexcept = default; DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default; }; struct MoveCtorOnly { MoveCtorOnly() noexcept = delete; MoveCtorOnly(const MoveCtorOnly&) noexcept = delete; MoveCtorOnly(MoveCtorOnly&&) noexcept { } MoveCtorOnly& operator=(const MoveCtorOnly&) noexcept = delete; MoveCtorOnly& operator=(MoveCtorOnly&&) noexcept = delete; }; struct MoveCtorAndSwapOnly : MoveCtorOnly { }; void swap(MoveCtorAndSwapOnly&, MoveCtorAndSwapOnly&) { } struct DeletedMoves { DeletedMoves() = default; DeletedMoves(const DeletedMoves&) = default; DeletedMoves(DeletedMoves&&) = delete; DeletedMoves& operator=(const DeletedMoves&) = default; DeletedMoves& operator=(DeletedMoves&&) = delete; }; struct nonliteral { nonliteral() { } bool operator<(const nonliteral&) const; bool operator<=(const nonliteral&) const; bool operator==(const nonliteral&) const; bool operator!=(const nonliteral&) const; bool operator>=(const nonliteral&) const; bool operator>(const nonliteral&) const; }; void default_ctor() { static_assert(is_default_constructible_v>); static_assert(is_default_constructible_v>); static_assert(!is_default_constructible_v>); static_assert(is_default_constructible_v>); static_assert(is_default_constructible_v>); static_assert(noexcept(variant())); static_assert(!noexcept(variant())); static_assert(noexcept(variant())); } void copy_ctor() { static_assert(is_copy_constructible_v>); static_assert(!is_copy_constructible_v>); static_assert(is_trivially_copy_constructible_v>); static_assert(!is_trivially_copy_constructible_v>); static_assert(is_trivially_copy_constructible_v>); { variant a; static_assert(noexcept(variant(a))); } { variant a; static_assert(!noexcept(variant(a))); } { variant a; static_assert(!noexcept(variant(a))); } { variant a; static_assert(noexcept(variant(a))); } } void move_ctor() { static_assert(is_move_constructible_v>); static_assert(!is_move_constructible_v>); static_assert(is_move_constructible_v>); // uses copy ctor static_assert(is_trivially_move_constructible_v>); static_assert(!is_trivially_move_constructible_v>); static_assert(!noexcept(variant(declval>()))); static_assert(noexcept(variant(declval>()))); } void arbitrary_ctor() { static_assert(!is_constructible_v, const char*>); static_assert(is_constructible_v, const char*>); static_assert(noexcept(variant(int{}))); static_assert(noexcept(variant(int{}))); static_assert(!noexcept(variant(Empty{}))); static_assert(noexcept(variant(DefaultNoexcept{}))); } struct none { none() = delete; }; struct any { template any(T&&) {} }; void in_place_index_ctor() { variant a(in_place_index<0>, "a"); variant b(in_place_index<1>, {'a'}); static_assert(!is_constructible_v, std::in_place_index_t<0>>, "PR libstdc++/90165"); } void in_place_type_ctor() { variant a(in_place_type, "a"); variant b(in_place_type, {'a'}); static_assert(!is_constructible_v, in_place_type_t, const char*>); static_assert(!is_constructible_v, std::in_place_type_t>, "PR libstdc++/90165"); } void dtor() { static_assert(is_destructible_v>); static_assert(is_destructible_v>); } void copy_assign() { static_assert(is_copy_assignable_v>); static_assert(!is_copy_assignable_v>); static_assert(is_trivially_copy_assignable_v>); static_assert(!is_trivially_copy_assignable_v>); static_assert(is_trivially_copy_assignable_v>); { variant a; static_assert(!noexcept(a = a)); } { variant a; static_assert(noexcept(a = a)); } } void move_assign() { static_assert(is_move_assignable_v>); static_assert(!is_move_assignable_v>); static_assert(is_move_assignable_v>); // uses copy assignment static_assert(is_trivially_move_assignable_v>); static_assert(!is_trivially_move_assignable_v>); { variant a; static_assert(!noexcept(a = std::move(a))); } { variant a; static_assert(noexcept(a = std::move(a))); } } void arbitrary_assign() { static_assert(!is_assignable_v, const char*>); static_assert(is_assignable_v, const char*>); static_assert(noexcept(variant() = int{})); static_assert(noexcept(variant() = int{})); static_assert(!noexcept(variant() = Empty{})); static_assert(noexcept(variant() = DefaultNoexcept{})); } void test_get() { static_assert(is_same(variant())), int&&>::value); static_assert(is_same(variant())), string&&>::value); static_assert(is_same(variant())), const string&&>::value); static_assert(is_same(variant())), int&&>::value); static_assert(is_same(variant())), string&&>::value); static_assert(is_same(variant())), const string&&>::value); } void test_relational() { { constexpr variant a(42), b(43); static_assert((a < b)); static_assert(!(a > b)); static_assert((a <= b)); static_assert(!(a == b)); static_assert((a != b)); static_assert(!(a >= b)); } { constexpr variant a(42), b(42); static_assert(!(a < b)); static_assert(!(a > b)); static_assert((a <= b)); static_assert((a == b)); static_assert(!(a != b)); static_assert((a >= b)); } { constexpr variant a(43), b(42); static_assert(!(a < b)); static_assert((a > b)); static_assert(!(a <= b)); static_assert(!(a == b)); static_assert((a != b)); static_assert((a >= b)); } { constexpr monostate a, b; static_assert(!(a < b)); static_assert(!(a > b)); static_assert((a <= b)); static_assert((a == b)); static_assert(!(a != b)); static_assert((a >= b)); } } // Not swappable, and variant not swappable via the generic std::swap. struct C { }; void swap(C&, C&) = delete; static_assert( !std::is_swappable_v> ); static_assert( !std::is_swappable_v> ); static_assert( !std::is_swappable_v> ); // Not swappable, and variant not swappable via the generic std::swap. struct D { D(D&&) = delete; }; static_assert( !std::is_swappable_v> ); static_assert( !std::is_swappable_v> ); static_assert( !std::is_swappable_v> ); void test_swap() { static_assert(is_swappable_v>); static_assert(!is_swappable_v>); static_assert(is_swappable_v>); static_assert(!is_swappable_v>); } void test_visit() { { struct Visitor { void operator()(monostate) {} void operator()(const int&) {} }; struct CVisitor { void operator()(monostate) const {} void operator()(const int&) const {} }; } { struct Visitor { bool operator()(int, float) { return false; } bool operator()(int, double) { return false; } bool operator()(char, float) { return false; } bool operator()(char, double) { return false; } }; visit(Visitor(), variant(), variant()); } { struct Visitor { constexpr bool operator()(const int&) { return true; } constexpr bool operator()(const nonliteral&) { return false; } }; static_assert(visit(Visitor(), variant(0))); } { struct Visitor { constexpr bool operator()(const int&) { return true; } constexpr bool operator()(const nonliteral&) { return false; } }; static_assert(visit(Visitor(), variant(0))); } // PR libstdc++/79513 { std::variant v [[gnu::unused]] (5); std::visit([](int&){}, v); std::visit([](int&&){}, std::move(v)); } } void test_constexpr() { constexpr variant a; static_assert(holds_alternative(a)); constexpr variant b(in_place_index<0>, int{}); static_assert(holds_alternative(b)); constexpr variant c(in_place_type, int{}); static_assert(holds_alternative(c)); constexpr variant d(in_place_index<1>, char{}); static_assert(holds_alternative(d)); constexpr variant e(in_place_type, char{}); static_assert(holds_alternative(e)); constexpr variant f(char{}); static_assert(holds_alternative(f)); { struct literal { constexpr literal() = default; }; constexpr variant v{}; constexpr variant v1{in_place_type}; constexpr variant v2{in_place_index<0>}; } { constexpr variant a(42); static_assert(get<0>(a) == 42); } { constexpr variant a(42); static_assert(get<0>(a) == 42); } { constexpr variant a(42); static_assert(get<1>(a) == 42); } { constexpr variant a(42); static_assert(get(a) == 42); } { constexpr variant a(42); static_assert(get(a) == 42); } { constexpr variant a(42); static_assert(get(a) == 42); } { constexpr variant a(42); static_assert(get<0>(std::move(a)) == 42); } { constexpr variant a(42); static_assert(get<0>(std::move(a)) == 42); } { constexpr variant a(42); static_assert(get<1>(std::move(a)) == 42); } { constexpr variant a(42); static_assert(get(std::move(a)) == 42); } { constexpr variant a(42); static_assert(get(std::move(a)) == 42); } { constexpr variant a(42); static_assert(get(std::move(a)) == 42); } } void test_pr77641() { struct X { constexpr X() { } }; constexpr std::variant v1 = X{}; } namespace adl_trap { struct X { X() = default; X(int) { } X(std::initializer_list, const X&) { } }; template void move(T&) { } template void forward(T&) { } struct Visitor { template void operator()(T&&) { } }; } void test_adl() { using adl_trap::X; X x; std::initializer_list il; adl_trap::Visitor vis; std::variant v0(x); v0 = x; v0.emplace<0>(x); v0.emplace<0>(il, x); visit(vis, v0); variant v1{in_place_index<0>, x}; variant v2{in_place_type, x}; variant v3{in_place_index<0>, il, x}; variant v4{in_place_type, il, x}; } void test_variant_alternative() { static_assert(is_same_v>, int>); static_assert(is_same_v>, string>); static_assert(is_same_v>, const int>); static_assert(is_same_v>, volatile int>); static_assert(is_same_v>, const volatile int>); } template constexpr auto has_type_emplace(int) -> decltype((declval().template emplace(), true)) { return true; }; template constexpr bool has_type_emplace(...) { return false; }; template constexpr auto has_index_emplace(int) -> decltype((declval().template emplace(), true)) { return true; }; template constexpr bool has_index_emplace(...) { return false; }; void test_emplace() { static_assert(has_type_emplace, int>(0)); static_assert(!has_type_emplace, int>(0)); static_assert(has_index_emplace, 0>(0)); static_assert(!has_type_emplace, AllDeleted>(0)); static_assert(!has_index_emplace, 0>(0)); static_assert(has_type_emplace, int>(0)); static_assert(has_index_emplace, 0>(0)); static_assert(has_type_emplace, AllDeleted>, vector>(0)); static_assert(has_index_emplace, AllDeleted>, 1>(0)); // The above tests only check the emplace members are available for // overload resolution. The following odr-uses will instantiate them: variant, AllDeleted> v; v.emplace<0>(1); v.emplace(1); v.emplace<1>(1, 1); v.emplace>(1, 1); v.emplace<1>({1, 2, 3, 4}); v.emplace>({1, 2, 3, 4}); } void test_triviality() { #define TEST_TEMPLATE(DT, CC, MC, CA, MA, CC_VAL, MC_VAL, CA_VAL, MA_VAL) \ { \ struct A \ { \ ~A() DT; \ A(const A&) CC; \ A(A&&) MC; \ A& operator=(const A&) CA; \ A& operator=(A&&) MA; \ }; \ static_assert(CC_VAL == is_trivially_copy_constructible_v>); \ static_assert(MC_VAL == is_trivially_move_constructible_v>); \ static_assert(CA_VAL == is_trivially_copy_assignable_v>); \ static_assert(MA_VAL == is_trivially_move_assignable_v>); \ } TEST_TEMPLATE(=default, =default, =default, =default, =default, true, true, true, true) TEST_TEMPLATE(=default, =default, =default, =default, , true, true, true, false) TEST_TEMPLATE(=default, =default, =default, , =default, true, true, false, true) TEST_TEMPLATE(=default, =default, =default, , , true, true, false, false) TEST_TEMPLATE(=default, =default, , =default, =default, true, false, true, false) TEST_TEMPLATE(=default, =default, , =default, , true, false, true, false) TEST_TEMPLATE(=default, =default, , , =default, true, false, false, false) TEST_TEMPLATE(=default, =default, , , , true, false, false, false) TEST_TEMPLATE(=default, , =default, =default, =default, false, true, false, true) TEST_TEMPLATE(=default, , =default, =default, , false, true, false, false) TEST_TEMPLATE(=default, , =default, , =default, false, true, false, true) TEST_TEMPLATE(=default, , =default, , , false, true, false, false) TEST_TEMPLATE(=default, , , =default, =default, false, false, false, false) TEST_TEMPLATE(=default, , , =default, , false, false, false, false) TEST_TEMPLATE(=default, , , , =default, false, false, false, false) TEST_TEMPLATE(=default, , , , , false, false, false, false) TEST_TEMPLATE( , =default, =default, =default, =default, false, false, false, false) TEST_TEMPLATE( , =default, =default, =default, , false, false, false, false) TEST_TEMPLATE( , =default, =default, , =default, false, false, false, false) TEST_TEMPLATE( , =default, =default, , , false, false, false, false) TEST_TEMPLATE( , =default, , =default, =default, false, false, false, false) TEST_TEMPLATE( , =default, , =default, , false, false, false, false) TEST_TEMPLATE( , =default, , , =default, false, false, false, false) TEST_TEMPLATE( , =default, , , , false, false, false, false) TEST_TEMPLATE( , , =default, =default, =default, false, false, false, false) TEST_TEMPLATE( , , =default, =default, , false, false, false, false) TEST_TEMPLATE( , , =default, , =default, false, false, false, false) TEST_TEMPLATE( , , =default, , , false, false, false, false) TEST_TEMPLATE( , , , =default, =default, false, false, false, false) TEST_TEMPLATE( , , , =default, , false, false, false, false) TEST_TEMPLATE( , , , , =default, false, false, false, false) TEST_TEMPLATE( , , , , , false, false, false, false) #undef TEST_TEMPLATE #define TEST_TEMPLATE(CC, MC, CA, MA) \ { \ struct A \ { \ A(const A&) CC; \ A(A&&) MC; \ A& operator=(const A&) CA; \ A& operator=(A&&) MA; \ }; \ static_assert(!is_trivially_copy_constructible_v>); \ static_assert(!is_trivially_move_constructible_v>); \ static_assert(!is_trivially_copy_assignable_v>); \ static_assert(!is_trivially_move_assignable_v>); \ } TEST_TEMPLATE(=default, =default, =default, =default) TEST_TEMPLATE(=default, =default, =default, ) TEST_TEMPLATE(=default, =default, , =default) TEST_TEMPLATE(=default, =default, , ) TEST_TEMPLATE(=default, , =default, =default) TEST_TEMPLATE(=default, , =default, ) TEST_TEMPLATE(=default, , , =default) TEST_TEMPLATE(=default, , , ) TEST_TEMPLATE( , =default, =default, =default) TEST_TEMPLATE( , =default, =default, ) TEST_TEMPLATE( , =default, , =default) TEST_TEMPLATE( , =default, , ) TEST_TEMPLATE( , , =default, =default) TEST_TEMPLATE( , , =default, ) TEST_TEMPLATE( , , , =default) TEST_TEMPLATE( , , , ) #undef TEST_TEMPLATE static_assert(is_trivially_copy_constructible_v>); static_assert(is_trivially_move_constructible_v>); static_assert(is_trivially_copy_assignable_v>); static_assert(is_trivially_move_assignable_v>); }