Eric Fiselier 273857d1ea Harden variant test added in r366022
The test was brittle since it only went boom for one specific type, when
really it should go boom for all of them.

llvm-svn: 366025
2019-07-14 18:30:34 +00:00

199 lines
5.4 KiB
C++

// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11, c++14
// XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions
// <variant>
// template <class ...Types> class variant;
// template <class T> constexpr variant(T&&) noexcept(see below);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include <memory>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
struct Dummy {
Dummy() = default;
};
struct ThrowsT {
ThrowsT(int) noexcept(false) {}
};
struct NoThrowT {
NoThrowT(int) noexcept(true) {}
};
struct AnyConstructible { template <typename T> AnyConstructible(T&&) {} };
struct NoConstructible { NoConstructible() = delete; };
template <class T>
struct RValueConvertibleFrom { RValueConvertibleFrom(T&&) {} };
void test_T_ctor_noexcept() {
{
using V = std::variant<Dummy, NoThrowT>;
static_assert(std::is_nothrow_constructible<V, int>::value, "");
}
{
using V = std::variant<Dummy, ThrowsT>;
static_assert(!std::is_nothrow_constructible<V, int>::value, "");
}
}
void test_T_ctor_sfinae() {
{
using V = std::variant<long, long long>;
static_assert(!std::is_constructible<V, int>::value, "ambiguous");
}
{
using V = std::variant<std::string, std::string>;
static_assert(!std::is_constructible<V, const char *>::value, "ambiguous");
}
{
using V = std::variant<std::string, void *>;
static_assert(!std::is_constructible<V, int>::value,
"no matching constructor");
}
{
using V = std::variant<std::string, float>;
static_assert(std::is_constructible<V, int>::value == VariantAllowsNarrowingConversions,
"no matching constructor");
}
{
using V = std::variant<std::unique_ptr<int>, bool>;
static_assert(!std::is_constructible<V, std::unique_ptr<char>>::value,
"no explicit bool in constructor");
struct X {
operator void*();
};
static_assert(!std::is_constructible<V, X>::value,
"no boolean conversion in constructor");
static_assert(!std::is_constructible<V, std::false_type>::value,
"no converted to bool in constructor");
}
{
struct X {};
struct Y {
operator X();
};
using V = std::variant<X>;
static_assert(std::is_constructible<V, Y>::value,
"regression on user-defined conversions in constructor");
}
{
using V = std::variant<AnyConstructible, NoConstructible>;
static_assert(
!std::is_constructible<V, std::in_place_type_t<NoConstructible>>::value,
"no matching constructor");
static_assert(!std::is_constructible<V, std::in_place_index_t<1>>::value,
"no matching constructor");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int, int &&>;
static_assert(!std::is_constructible<V, int>::value, "ambiguous");
}
{
using V = std::variant<int, const int &>;
static_assert(!std::is_constructible<V, int>::value, "ambiguous");
}
#endif
}
void test_T_ctor_basic() {
{
constexpr std::variant<int> v(42);
static_assert(v.index() == 0, "");
static_assert(std::get<0>(v) == 42, "");
}
{
constexpr std::variant<int, long> v(42l);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v) == 42, "");
}
#ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
{
constexpr std::variant<unsigned, long> v(42);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v) == 42, "");
}
#endif
{
std::variant<std::string, bool const> v = "foo";
assert(v.index() == 0);
assert(std::get<0>(v) == "foo");
}
{
std::variant<bool volatile, std::unique_ptr<int>> v = nullptr;
assert(v.index() == 1);
assert(std::get<1>(v) == nullptr);
}
{
std::variant<bool volatile const, int> v = true;
assert(v.index() == 0);
assert(std::get<0>(v));
}
{
std::variant<RValueConvertibleFrom<int>> v1 = 42;
assert(v1.index() == 0);
int x = 42;
std::variant<RValueConvertibleFrom<int>, AnyConstructible> v2 = x;
assert(v2.index() == 1);
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<const int &, int &&, long>;
static_assert(std::is_convertible<int &, V>::value, "must be implicit");
int x = 42;
V v(x);
assert(v.index() == 0);
assert(&std::get<0>(v) == &x);
}
{
using V = std::variant<const int &, int &&, long>;
static_assert(std::is_convertible<int, V>::value, "must be implicit");
int x = 42;
V v(std::move(x));
assert(v.index() == 1);
assert(&std::get<1>(v) == &x);
}
#endif
}
struct BoomOnAnything {
template <class T>
constexpr BoomOnAnything(T) { static_assert(!std::is_same<T, T>::value, ""); }
};
void test_no_narrowing_check_for_class_types() {
using V = std::variant<int, BoomOnAnything>;
V v(42);
assert(v.index() == 0);
assert(std::get<0>(v) == 42);
}
int main(int, char**) {
test_T_ctor_basic();
test_T_ctor_noexcept();
test_T_ctor_sfinae();
test_no_narrowing_check_for_class_types();
return 0;
}