gcc/libstdc++-v3/testsuite/20_util/variant/compile.cc
Jonathan Wakely 2bbacc18b3 libstdc++: Rename test type to avoid clashing with std::any
When PCH are enabled this test file includes <any> and so the
using-directive brings std::any into the global scope. It isn't
currently a problem, because the -std option in the dg-options means
that PCH is not used. If that option is removed, the test fails with PCH
and passes without.

This just renames the type to avoid the name classh (and also the 'none'
type for consistency).

libstdc++-v3/ChangeLog:

	* testsuite/20_util/variant/compile.cc: Rename 'any' to avoid
	clash with std::any.
2021-05-10 15:00:06 +01:00

619 lines
21 KiB
C++

// { dg-options "-std=gnu++17" }
// { dg-do compile { target c++17 } }
// Copyright (C) 2016-2021 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
// <http://www.gnu.org/licenses/>.
#include <variant>
#include <string>
#include <vector>
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;
};
struct virtual_default_dtor {
virtual ~virtual_default_dtor() = default;
};
void default_ctor()
{
static_assert(is_default_constructible_v<variant<int, string>>);
static_assert(is_default_constructible_v<variant<string, string>>);
static_assert(!is_default_constructible_v<variant<AllDeleted, string>>);
static_assert(is_default_constructible_v<variant<string, AllDeleted>>);
static_assert(is_default_constructible_v<variant<DeletedMoves>>);
static_assert(noexcept(variant<int>()));
static_assert(!noexcept(variant<Empty>()));
static_assert(noexcept(variant<DefaultNoexcept>()));
{
variant<virtual_default_dtor> a;
}
}
void copy_ctor()
{
static_assert(is_copy_constructible_v<variant<int, string>>);
static_assert(!is_copy_constructible_v<variant<AllDeleted, string>>);
static_assert(is_trivially_copy_constructible_v<variant<int>>);
static_assert(!is_trivially_copy_constructible_v<variant<std::string>>);
static_assert(is_trivially_copy_constructible_v<variant<DeletedMoves>>);
{
variant<int> a;
static_assert(noexcept(variant<int>(a)));
}
{
variant<string> a;
static_assert(!noexcept(variant<string>(a)));
}
{
variant<int, string> a;
static_assert(!noexcept(variant<int, string>(a)));
}
{
variant<int, char> a;
static_assert(noexcept(variant<int, char>(a)));
}
}
void move_ctor()
{
static_assert(is_move_constructible_v<variant<int, string>>);
static_assert(!is_move_constructible_v<variant<AllDeleted, string>>);
static_assert(is_move_constructible_v<variant<int, DeletedMoves>>); // uses copy ctor
static_assert(is_trivially_move_constructible_v<variant<int>>);
static_assert(!is_trivially_move_constructible_v<variant<std::string>>);
static_assert(!noexcept(variant<int, Empty>(declval<variant<int, Empty>>())));
static_assert(noexcept(variant<int, DefaultNoexcept>(declval<variant<int, DefaultNoexcept>>())));
}
void arbitrary_ctor()
{
static_assert(!is_constructible_v<variant<string, string>, const char*>);
static_assert(is_constructible_v<variant<int, string>, const char*>);
static_assert(noexcept(variant<int, Empty>(int{})));
static_assert(noexcept(variant<int, DefaultNoexcept>(int{})));
static_assert(!noexcept(variant<int, Empty>(Empty{})));
static_assert(noexcept(variant<int, DefaultNoexcept>(DefaultNoexcept{})));
// P0608R3 disallow narrowing conversions and boolean conversions
static_assert(!is_constructible_v<variant<float>, int>);
static_assert(!is_constructible_v<variant<float, vector<int>>, int>);
static_assert(is_constructible_v<variant<float, int>, char>);
static_assert(!is_constructible_v<variant<float, char>, int>);
static_assert(is_constructible_v<variant<float, long>, int>);
struct big_int { big_int(int) { } };
static_assert(is_constructible_v<variant<float, big_int>, int>);
static_assert(!is_constructible_v<variant<int>, unsigned>);
static_assert(!is_constructible_v<variant<bool>, int>);
static_assert(!is_constructible_v<variant<bool>, void*>);
// P1957R2 Converting from T* to bool should be considered narrowing
struct ConvertibleToBool
{
operator bool() const { return true; }
};
static_assert(is_constructible_v<variant<bool>, ConvertibleToBool>);
static_assert(is_constructible_v<variant<bool, int>, ConvertibleToBool>);
}
struct None { None() = delete; };
struct Any { template <typename T> Any(T&&) {} };
void in_place_index_ctor()
{
variant<string, string> a(in_place_index<0>, "a");
variant<string, string> b(in_place_index<1>, {'a'});
static_assert(!is_constructible_v<variant<None, Any>, std::in_place_index_t<0>>, "PR libstdc++/90165");
}
void in_place_type_ctor()
{
variant<int, string, int> a(in_place_type<string>, "a");
variant<int, string, int> b(in_place_type<string>, {'a'});
static_assert(!is_constructible_v<variant<string, string>, in_place_type_t<string>, const char*>);
static_assert(!is_constructible_v<variant<None, Any>, std::in_place_type_t<None>>, "PR libstdc++/90165");
}
void dtor()
{
static_assert(is_destructible_v<variant<int, string>>);
static_assert(is_destructible_v<variant<AllDeleted, string>>);
}
void copy_assign()
{
static_assert(is_copy_assignable_v<variant<int, string>>);
static_assert(!is_copy_assignable_v<variant<AllDeleted, string>>);
static_assert(is_trivially_copy_assignable_v<variant<int>>);
static_assert(!is_trivially_copy_assignable_v<variant<string>>);
static_assert(is_trivially_copy_assignable_v<variant<DeletedMoves>>);
{
variant<Empty> a;
static_assert(!noexcept(a = a));
}
{
variant<DefaultNoexcept> a;
static_assert(noexcept(a = a));
}
}
void move_assign()
{
static_assert(is_move_assignable_v<variant<int, string>>);
static_assert(!is_move_assignable_v<variant<AllDeleted, string>>);
static_assert(is_move_assignable_v<variant<int, DeletedMoves>>); // uses copy assignment
static_assert(is_trivially_move_assignable_v<variant<int>>);
static_assert(!is_trivially_move_assignable_v<variant<string>>);
{
variant<Empty> a;
static_assert(!noexcept(a = std::move(a)));
}
{
variant<DefaultNoexcept> a;
static_assert(noexcept(a = std::move(a)));
}
}
void arbitrary_assign()
{
static_assert(!is_assignable_v<variant<string, string>, const char*>);
static_assert(is_assignable_v<variant<int, string>, const char*>);
static_assert(noexcept(variant<int, Empty>() = int{}));
static_assert(noexcept(variant<int, DefaultNoexcept>() = int{}));
static_assert(!noexcept(variant<int, Empty>() = Empty{}));
static_assert(noexcept(variant<int, DefaultNoexcept>() = DefaultNoexcept{}));
}
void test_get()
{
static_assert(is_same<decltype(get<0>(variant<int, string>())), int&&>::value);
static_assert(is_same<decltype(get<1>(variant<int, string>())), string&&>::value);
static_assert(is_same<decltype(get<1>(variant<int, const string>())), const string&&>::value);
static_assert(is_same<decltype(get<int>(variant<int, string>())), int&&>::value);
static_assert(is_same<decltype(get<string>(variant<int, string>())), string&&>::value);
static_assert(is_same<decltype(get<const string>(variant<int, const string>())), const string&&>::value);
}
void test_relational()
{
{
constexpr variant<int, nonliteral> 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<int, nonliteral> 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<int, nonliteral> 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<C> not swappable via the generic std::swap.
struct C { };
void swap(C&, C&) = delete;
static_assert( !std::is_swappable_v<variant<C>> );
static_assert( !std::is_swappable_v<variant<int, C>> );
static_assert( !std::is_swappable_v<variant<C, int>> );
// Not swappable, and variant<D> not swappable via the generic std::swap.
struct D { D(D&&) = delete; };
static_assert( !std::is_swappable_v<variant<D>> );
static_assert( !std::is_swappable_v<variant<int, D>> );
static_assert( !std::is_swappable_v<variant<D, int>> );
void test_swap()
{
static_assert(is_swappable_v<variant<int, string>>);
static_assert(!is_swappable_v<variant<MoveCtorOnly>>);
static_assert(is_swappable_v<variant<MoveCtorAndSwapOnly>>);
static_assert(!is_swappable_v<variant<AllDeleted>>);
}
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<int, char>(), variant<float, double>());
}
{
struct Visitor
{
constexpr bool operator()(const int&) { return true; }
constexpr bool operator()(const nonliteral&) { return false; }
};
static_assert(visit(Visitor(), variant<int, nonliteral>(0)));
}
{
struct Visitor
{
constexpr bool operator()(const int&) { return true; }
constexpr bool operator()(const nonliteral&) { return false; }
};
static_assert(visit(Visitor(), variant<int, nonliteral>(0)));
}
// PR libstdc++/79513
{
std::variant<int> v [[gnu::unused]] (5);
std::visit([](int&){}, v);
std::visit([](int&&){}, std::move(v));
}
}
void test_constexpr()
{
constexpr variant<int> a;
static_assert(holds_alternative<int>(a));
constexpr variant<int, char> b(in_place_index<0>, int{});
static_assert(holds_alternative<int>(b));
constexpr variant<int, char> c(in_place_type<int>, int{});
static_assert(holds_alternative<int>(c));
constexpr variant<int, char> d(in_place_index<1>, char{});
static_assert(holds_alternative<char>(d));
constexpr variant<int, char> e(in_place_type<char>, char{});
static_assert(holds_alternative<char>(e));
constexpr variant<int, char> f(char{});
static_assert(holds_alternative<char>(f));
{
struct literal {
constexpr literal() = default;
};
constexpr variant<literal, nonliteral> v{};
constexpr variant<literal, nonliteral> v1{in_place_type<literal>};
constexpr variant<literal, nonliteral> v2{in_place_index<0>};
}
{
constexpr variant<int> a(42);
static_assert(get<0>(a) == 42);
}
{
constexpr variant<int, nonliteral> a(42);
static_assert(get<0>(a) == 42);
}
{
constexpr variant<nonliteral, int> a(42);
static_assert(get<1>(a) == 42);
}
{
constexpr variant<int> a(42);
static_assert(get<int>(a) == 42);
}
{
constexpr variant<int, nonliteral> a(42);
static_assert(get<int>(a) == 42);
}
{
constexpr variant<nonliteral, int> a(42);
static_assert(get<int>(a) == 42);
}
{
constexpr variant<int> a(42);
static_assert(get<0>(std::move(a)) == 42);
}
{
constexpr variant<int, nonliteral> a(42);
static_assert(get<0>(std::move(a)) == 42);
}
{
constexpr variant<nonliteral, int> a(42);
static_assert(get<1>(std::move(a)) == 42);
}
{
constexpr variant<int> a(42);
static_assert(get<int>(std::move(a)) == 42);
}
{
constexpr variant<int, nonliteral> a(42);
static_assert(get<int>(std::move(a)) == 42);
}
{
constexpr variant<nonliteral, int> a(42);
static_assert(get<int>(std::move(a)) == 42);
}
}
void test_pr77641()
{
struct X {
constexpr X() { }
};
constexpr std::variant<X> v1 = X{};
}
namespace adl_trap
{
struct X {
X() = default;
X(int) { }
X(std::initializer_list<int>, const X&) { }
};
template<typename T> void move(T&) { }
template<typename T> void forward(T&) { }
struct Visitor {
template<typename T> void operator()(T&&) { }
};
}
void test_adl()
{
using adl_trap::X;
X x;
std::initializer_list<int> il;
adl_trap::Visitor vis;
std::variant<X> v0(x);
v0 = x;
v0.emplace<0>(x);
v0.emplace<0>(il, x);
visit(vis, v0);
variant<X> v1{in_place_index<0>, x};
variant<X> v2{in_place_type<X>, x};
variant<X> v3{in_place_index<0>, il, x};
variant<X> v4{in_place_type<X>, il, x};
}
void test_variant_alternative()
{
static_assert(is_same_v<variant_alternative_t<0, variant<int, string>>, int>);
static_assert(is_same_v<variant_alternative_t<1, variant<int, string>>, string>);
static_assert(is_same_v<variant_alternative_t<0, const variant<int>>, const int>);
static_assert(is_same_v<variant_alternative_t<0, volatile variant<int>>, volatile int>);
static_assert(is_same_v<variant_alternative_t<0, const volatile variant<int>>, const volatile int>);
}
template<typename V, typename T>
constexpr auto has_type_emplace(int) -> decltype((declval<V>().template emplace<T>(), true))
{ return true; };
template<typename V, typename T>
constexpr bool has_type_emplace(...)
{ return false; };
template<typename V, size_t N>
constexpr auto has_index_emplace(int) -> decltype((declval<V>().template emplace<N>(), true))
{ return true; };
template<typename V, size_t T>
constexpr bool has_index_emplace(...)
{ return false; };
void test_emplace()
{
static_assert(has_type_emplace<variant<int>, int>(0));
static_assert(!has_type_emplace<variant<long>, int>(0));
static_assert(has_index_emplace<variant<int>, 0>(0));
static_assert(!has_type_emplace<variant<AllDeleted>, AllDeleted>(0));
static_assert(!has_index_emplace<variant<AllDeleted>, 0>(0));
static_assert(has_type_emplace<variant<int, AllDeleted>, int>(0));
static_assert(has_index_emplace<variant<int, AllDeleted>, 0>(0));
static_assert(has_type_emplace<variant<int, vector<int>, AllDeleted>, vector<int>>(0));
static_assert(has_index_emplace<variant<int, vector<int>, AllDeleted>, 1>(0));
// The above tests only check the emplace members are available for
// overload resolution. The following odr-uses will instantiate them:
variant<int, vector<int>, AllDeleted> v;
v.emplace<0>(1);
v.emplace<int>(1);
v.emplace<1>(1, 1);
v.emplace<vector<int>>(1, 1);
v.emplace<1>({1, 2, 3, 4});
v.emplace<vector<int>>({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<variant<A>>); \
static_assert(MC_VAL == is_trivially_move_constructible_v<variant<A>>); \
static_assert(CA_VAL == is_trivially_copy_assignable_v<variant<A>>); \
static_assert(MA_VAL == is_trivially_move_assignable_v<variant<A>>); \
}
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<variant<AllDeleted, A>>); \
static_assert(!is_trivially_move_constructible_v<variant<AllDeleted, A>>); \
static_assert(!is_trivially_copy_assignable_v<variant<AllDeleted, A>>); \
static_assert(!is_trivially_move_assignable_v<variant<AllDeleted, A>>); \
}
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<variant<DefaultNoexcept, int, char, float, double>>);
static_assert(is_trivially_move_constructible_v<variant<DefaultNoexcept, int, char, float, double>>);
static_assert(is_trivially_copy_assignable_v<variant<DefaultNoexcept, int, char, float, double>>);
static_assert(is_trivially_move_assignable_v<variant<DefaultNoexcept, int, char, float, double>>);
}