// { 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>);
}