Add <variant> tests but disable them for libc++

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@287728 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2016-11-23 01:02:51 +00:00
parent fb6164cdad
commit 0373708cdc
42 changed files with 5067 additions and 1 deletions

View File

@@ -233,6 +233,7 @@ class Configuration(object):
self.lit_config.fatal( self.lit_config.fatal(
'unsupported value for "cxx_stdlib_under_test": %s' 'unsupported value for "cxx_stdlib_under_test": %s'
% self.cxx_stdlib_under_test) % self.cxx_stdlib_under_test)
self.config.available_features.add(self.cxx_stdlib_under_test)
if self.cxx_stdlib_under_test == 'libstdc++': if self.cxx_stdlib_under_test == 'libstdc++':
self.config.available_features.add('libstdc++') self.config.available_features.add('libstdc++')
# Manually enable the experimental and filesystem tests for libstdc++ # Manually enable the experimental and filesystem tests for libstdc++

View File

@@ -0,0 +1,5 @@
# FIXME: Libc++ does not yet implement variant but other STLs benefit from
# having our tests in-tree. This must be removed when <variant> is added.
if 'libc++' in config.available_features:
config.unsupported = True

View File

@@ -0,0 +1,37 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
/*
class bad_variant_access : public exception {
public:
bad_variant_access() noexcept;
virtual const char* what() const noexcept;
};
*/
#include <cassert>
#include <exception>
#include <type_traits>
#include <variant>
int main() {
static_assert(std::is_base_of<std::exception, std::bad_variant_access>::value,
"");
static_assert(noexcept(std::bad_variant_access{}), "must be noexcept");
static_assert(noexcept(std::bad_variant_access{}.what()), "must be noexcept");
std::bad_variant_access ex;
assert(ex.what());
}

View File

@@ -0,0 +1,11 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
int main() {}

View File

@@ -0,0 +1,132 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <size_t I, class... Types>
// constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>>
// get_if(variant<Types...>* v) noexcept;
// template <size_t I, class... Types>
// constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
// get_if(const variant<Types...>* v) noexcept;
#include "test_macros.h"
#include "variant_test_helpers.hpp"
#include <cassert>
#include <memory>
#include <variant>
void test_const_get_if() {
{
using V = std::variant<int>;
constexpr const V *v = nullptr;
static_assert(std::get_if<0>(v) == nullptr, "");
}
{
using V = std::variant<int, long>;
constexpr V v(42);
ASSERT_NOEXCEPT(std::get_if<0>(&v));
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), int const *);
static_assert(*std::get_if<0>(&v) == 42, "");
static_assert(std::get_if<1>(&v) == nullptr, "");
}
{
using V = std::variant<int, long>;
constexpr V v(42l);
ASSERT_SAME_TYPE(decltype(std::get_if<1>(&v)), long const *);
static_assert(*std::get_if<1>(&v) == 42, "");
static_assert(std::get_if<0>(&v) == nullptr, "");
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
const V v(x);
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), int *);
assert(std::get_if<0>(&v) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), int *);
assert(std::get_if<0>(&v) == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), const int *);
assert(std::get_if<0>(&v) == &x);
}
#endif
}
void test_get_if() {
{
using V = std::variant<int>;
V *v = nullptr;
assert(std::get_if<0>(v) == nullptr);
}
{
using V = std::variant<int, long>;
V v(42);
ASSERT_NOEXCEPT(std::get_if<0>(&v));
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), int *);
assert(*std::get_if<0>(&v) == 42);
assert(std::get_if<1>(&v) == nullptr);
}
{
using V = std::variant<int, long>;
V v(42l);
ASSERT_SAME_TYPE(decltype(std::get_if<1>(&v)), long *);
assert(*std::get_if<1>(&v) == 42);
assert(std::get_if<0>(&v) == nullptr);
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), int *);
assert(std::get_if<0>(&v) == &x);
}
{
using V = std::variant<const int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), const int *);
assert(std::get_if<0>(&v) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), int *);
assert(std::get_if<0>(&v) == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get_if<0>(&v)), const int *);
assert(std::get_if<0>(&v) == &x);
}
#endif
}
int main() {
test_const_get_if();
test_get_if();
}

View File

@@ -0,0 +1,130 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class T, class... Types>
// constexpr add_pointer_t<T> get_if(variant<Types...>* v) noexcept;
// template <class T, class... Types>
// constexpr add_pointer_t<const T> get_if(const variant<Types...>* v)
// noexcept;
#include "test_macros.h"
#include "variant_test_helpers.hpp"
#include <cassert>
#include <variant>
void test_const_get_if() {
{
using V = std::variant<int>;
constexpr const V *v = nullptr;
static_assert(std::get_if<int>(v) == nullptr, "");
}
{
using V = std::variant<int, long>;
constexpr V v(42);
ASSERT_NOEXCEPT(std::get_if<int>(&v));
ASSERT_SAME_TYPE(decltype(std::get_if<int>(&v)), int const *);
static_assert(*std::get_if<int>(&v) == 42, "");
static_assert(std::get_if<long>(&v) == nullptr, "");
}
{
using V = std::variant<int, long>;
constexpr V v(42l);
ASSERT_SAME_TYPE(decltype(std::get_if<long>(&v)), long const *);
static_assert(*std::get_if<long>(&v) == 42, "");
static_assert(std::get_if<int>(&v) == nullptr, "");
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
const V v(x);
ASSERT_SAME_TYPE(decltype(std::get_if<int &>(&v)), int *);
assert(std::get_if<int &>(&v) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get_if<int &&>(&v)), int *);
assert(std::get_if<int &&>(&v) == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get_if<const int &&>(&v)), const int *);
assert(std::get_if<const int &&>(&v) == &x);
}
#endif
}
void test_get_if() {
{
using V = std::variant<int>;
V *v = nullptr;
assert(std::get_if<int>(v) == nullptr);
}
{
using V = std::variant<int, long>;
V v(42);
ASSERT_NOEXCEPT(std::get_if<int>(&v));
ASSERT_SAME_TYPE(decltype(std::get_if<int>(&v)), int *);
assert(*std::get_if<int>(&v) == 42);
assert(std::get_if<long>(&v) == nullptr);
}
{
using V = std::variant<int, long>;
V v(42l);
ASSERT_SAME_TYPE(decltype(std::get_if<long>(&v)), long *);
assert(*std::get_if<long>(&v) == 42);
assert(std::get_if<int>(&v) == nullptr);
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get_if<int &>(&v)), int *);
assert(std::get_if<int &>(&v) == &x);
}
{
using V = std::variant<const int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get_if<const int &>(&v)), const int *);
assert(std::get_if<const int &>(&v) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get_if<int &&>(&v)), int *);
assert(std::get_if<int &&>(&v) == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get_if<const int &&>(&v)), const int *);
assert(std::get_if<const int &&>(&v) == &x);
}
#endif
}
int main() {
test_const_get_if();
test_get_if();
}

View File

@@ -0,0 +1,268 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <size_t I, class... Types>
// constexpr variant_alternative_t<I, variant<Types...>>&
// get(variant<Types...>& v);
// template <size_t I, class... Types>
// constexpr variant_alternative_t<I, variant<Types...>>&&
// get(variant<Types...>&& v);
// template <size_t I, class... Types>
// constexpr variant_alternative_t<I, variant<Types...>> const& get(const
// variant<Types...>& v);
// template <size_t I, class... Types>
// constexpr variant_alternative_t<I, variant<Types...>> const&& get(const
// variant<Types...>&& v);
#include "test_macros.h"
#include "variant_test_helpers.hpp"
#include <cassert>
#include <type_traits>
#include <utility>
#include <variant>
void test_const_lvalue_get() {
{
using V = std::variant<int>;
constexpr V v(42);
// ASSERT_NOT_NOEXCEPT(std::get<0>(v));
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int const &);
static_assert(std::get<0>(v) == 42, "");
}
{
using V = std::variant<int, long>;
constexpr V v(42l);
ASSERT_SAME_TYPE(decltype(std::get<1>(v)), long const &);
static_assert(std::get<1>(v) == 42, "");
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
const V v(x);
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int &);
assert(&std::get<0>(v) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int &);
assert(&std::get<0>(v) == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int &);
assert(&std::get<0>(v) == &x);
}
#endif
}
void test_lvalue_get() {
{
using V = std::variant<int>;
V v(42);
ASSERT_NOT_NOEXCEPT(std::get<0>(v));
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int &);
assert(std::get<0>(v) == 42);
}
{
using V = std::variant<int, long>;
V v(42l);
ASSERT_SAME_TYPE(decltype(std::get<1>(v)), long &);
assert(std::get<1>(v) == 42);
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int &);
assert(&std::get<0>(v) == &x);
}
{
using V = std::variant<const int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int &);
assert(&std::get<0>(v) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int &);
assert(&std::get<0>(v) == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), const int &);
assert(&std::get<0>(v) == &x);
}
#endif
}
void test_rvalue_get() {
{
using V = std::variant<int>;
V v(42);
ASSERT_NOT_NOEXCEPT(std::get<0>(std::move(v)));
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int &&);
assert(std::get<0>(std::move(v)) == 42);
}
{
using V = std::variant<int, long>;
V v(42l);
ASSERT_SAME_TYPE(decltype(std::get<1>(std::move(v))), long &&);
assert(std::get<1>(std::move(v)) == 42);
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int &);
assert(&std::get<0>(std::move(v)) == &x);
}
{
using V = std::variant<const int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int &);
assert(&std::get<0>(std::move(v)) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int &&);
int &&xref = std::get<0>(std::move(v));
assert(&xref == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int &&);
const int &&xref = std::get<0>(std::move(v));
assert(&xref == &x);
}
#endif
}
void test_const_rvalue_get() {
{
using V = std::variant<int>;
const V v(42);
ASSERT_NOT_NOEXCEPT(std::get<0>(std::move(v)));
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int &&);
assert(std::get<0>(std::move(v)) == 42);
}
{
using V = std::variant<int, long>;
const V v(42l);
ASSERT_SAME_TYPE(decltype(std::get<1>(std::move(v))), const long &&);
assert(std::get<1>(std::move(v)) == 42);
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
const V v(x);
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int &);
assert(&std::get<0>(std::move(v)) == &x);
}
{
using V = std::variant<const int &>;
int x = 42;
const V v(x);
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int &);
assert(&std::get<0>(std::move(v)) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), int &&);
int &&xref = std::get<0>(std::move(v));
assert(&xref == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<0>(std::move(v))), const int &&);
const int &&xref = std::get<0>(std::move(v));
assert(&xref == &x);
}
#endif
}
template <std::size_t I> using Idx = std::integral_constant<size_t, I>;
void test_throws_for_all_value_categories() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using V = std::variant<int, long>;
V v0(42);
const V &cv0 = v0;
assert(v0.index() == 0);
V v1(42l);
const V &cv1 = v1;
assert(v1.index() == 1);
std::integral_constant<size_t, 0> zero;
std::integral_constant<size_t, 1> one;
auto test = [](auto idx, auto &&v) {
using Idx = decltype(idx);
try {
std::get<Idx::value>(std::forward<decltype(v)>(v));
} catch (std::bad_variant_access const &) {
return true;
} catch (...) { /* ... */
}
return false;
};
{ // lvalue test cases
assert(test(one, v0));
assert(test(zero, v1));
}
{ // const lvalue test cases
assert(test(one, cv0));
assert(test(zero, cv1));
}
{ // rvalue test cases
assert(test(one, std::move(v0)));
assert(test(zero, std::move(v1)));
}
{ // const rvalue test cases
assert(test(one, std::move(cv0)));
assert(test(zero, std::move(cv1)));
}
#endif
}
int main() {
test_const_lvalue_get();
test_lvalue_get();
test_rvalue_get();
test_const_rvalue_get();
test_throws_for_all_value_categories();
}

View File

@@ -0,0 +1,266 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class T, class... Types> constexpr T& get(variant<Types...>& v);
// template <class T, class... Types> constexpr T&& get(variant<Types...>&& v);
// template <class T, class... Types> constexpr const T& get(const
// variant<Types...>& v);
// template <class T, class... Types> constexpr const T&& get(const
// variant<Types...>&& v);
#include "test_macros.h"
#include "variant_test_helpers.hpp"
#include <cassert>
#include <type_traits>
#include <utility>
#include <variant>
void test_const_lvalue_get() {
{
using V = std::variant<int>;
constexpr V v(42);
// ASSERT_NOT_NOEXCEPT(std::get<int>(v));
ASSERT_SAME_TYPE(decltype(std::get<0>(v)), int const &);
static_assert(std::get<int>(v) == 42, "");
}
{
using V = std::variant<int, long>;
constexpr V v(42l);
ASSERT_SAME_TYPE(decltype(std::get<long>(v)), long const &);
static_assert(std::get<long>(v) == 42, "");
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
const V v(x);
ASSERT_SAME_TYPE(decltype(std::get<int &>(v)), int &);
assert(&std::get<int &>(v) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<int &&>(v)), int &);
assert(&std::get<int &&>(v) == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<const int &&>(v)), const int &);
assert(&std::get<const int &&>(v) == &x);
}
#endif
}
void test_lvalue_get() {
{
using V = std::variant<int>;
V v(42);
ASSERT_NOT_NOEXCEPT(std::get<int>(v));
ASSERT_SAME_TYPE(decltype(std::get<int>(v)), int &);
assert(std::get<int>(v) == 42);
}
{
using V = std::variant<int, long>;
V v(42l);
ASSERT_SAME_TYPE(decltype(std::get<long>(v)), long &);
assert(std::get<long>(v) == 42);
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get<int &>(v)), int &);
assert(&std::get<int &>(v) == &x);
}
{
using V = std::variant<const int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get<const int &>(v)), const int &);
assert(&std::get<const int &>(v) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<int &&>(v)), int &);
assert(&std::get<int &&>(v) == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<const int &&>(v)), const int &);
assert(&std::get<const int &&>(v) == &x);
}
#endif
}
void test_rvalue_get() {
{
using V = std::variant<int>;
V v(42);
ASSERT_NOT_NOEXCEPT(std::get<int>(std::move(v)));
ASSERT_SAME_TYPE(decltype(std::get<int>(std::move(v))), int &&);
assert(std::get<int>(std::move(v)) == 42);
}
{
using V = std::variant<int, long>;
V v(42l);
ASSERT_SAME_TYPE(decltype(std::get<long>(std::move(v))), long &&);
assert(std::get<long>(std::move(v)) == 42);
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get<int &>(std::move(v))), int &);
assert(&std::get<int &>(std::move(v)) == &x);
}
{
using V = std::variant<const int &>;
int x = 42;
V v(x);
ASSERT_SAME_TYPE(decltype(std::get<const int &>(std::move(v))),
const int &);
assert(&std::get<const int &>(std::move(v)) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<int &&>(std::move(v))), int &&);
int &&xref = std::get<int &&>(std::move(v));
assert(&xref == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<const int &&>(std::move(v))),
const int &&);
const int &&xref = std::get<const int &&>(std::move(v));
assert(&xref == &x);
}
#endif
}
void test_const_rvalue_get() {
{
using V = std::variant<int>;
const V v(42);
ASSERT_NOT_NOEXCEPT(std::get<int>(std::move(v)));
ASSERT_SAME_TYPE(decltype(std::get<int>(std::move(v))), const int &&);
assert(std::get<int>(std::move(v)) == 42);
}
{
using V = std::variant<int, long>;
const V v(42l);
ASSERT_SAME_TYPE(decltype(std::get<long>(std::move(v))), const long &&);
assert(std::get<long>(std::move(v)) == 42);
}
// FIXME: Remove these once reference support is reinstated
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &>;
int x = 42;
const V v(x);
ASSERT_SAME_TYPE(decltype(std::get<int &>(std::move(v))), int &);
assert(&std::get<int &>(std::move(v)) == &x);
}
{
using V = std::variant<const int &>;
int x = 42;
const V v(x);
ASSERT_SAME_TYPE(decltype(std::get<const int &>(std::move(v))),
const int &);
assert(&std::get<const int &>(std::move(v)) == &x);
}
{
using V = std::variant<int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<int &&>(std::move(v))), int &&);
int &&xref = std::get<int &&>(std::move(v));
assert(&xref == &x);
}
{
using V = std::variant<const int &&>;
int x = 42;
const V v(std::move(x));
ASSERT_SAME_TYPE(decltype(std::get<const int &&>(std::move(v))),
const int &&);
const int &&xref = std::get<const int &&>(std::move(v));
assert(&xref == &x);
}
#endif
}
template <class Tp> struct identity { using type = Tp; };
void test_throws_for_all_value_categories() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using V = std::variant<int, long>;
V v0(42);
const V &cv0 = v0;
assert(v0.index() == 0);
V v1(42l);
const V &cv1 = v1;
assert(v1.index() == 1);
identity<int> zero;
identity<long> one;
auto test = [](auto idx, auto &&v) {
using Idx = decltype(idx);
try {
std::get<typename Idx::type>(std::forward<decltype(v)>(v));
} catch (std::bad_variant_access const &) {
return true;
} catch (...) { /* ... */
}
return false;
};
{ // lvalue test cases
assert(test(one, v0));
assert(test(zero, v1));
}
{ // const lvalue test cases
assert(test(one, cv0));
assert(test(zero, cv1));
}
{ // rvalue test cases
assert(test(one, std::move(v0)));
assert(test(zero, std::move(v1)));
}
{ // const rvalue test cases
assert(test(one, std::move(cv0)));
assert(test(zero, std::move(cv1)));
}
#endif
}
int main() {
test_const_lvalue_get();
test_lvalue_get();
test_rvalue_get();
test_const_rvalue_get();
test_throws_for_all_value_categories();
}

View File

@@ -0,0 +1,37 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class T, class... Types>
// constexpr bool holds_alternative(const variant<Types...>& v) noexcept;
#include <variant>
int main() {
{
using V = std::variant<int>;
constexpr V v;
static_assert(std::holds_alternative<int>(v), "");
}
{
using V = std::variant<int, long>;
constexpr V v;
static_assert(std::holds_alternative<int>(v), "");
static_assert(!std::holds_alternative<long>(v), "");
}
{ // noexcept test
using V = std::variant<int>;
const V v;
static_assert(noexcept(std::holds_alternative<int>(v)), "must be noexcept");
}
}

View File

@@ -0,0 +1,112 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class... Types> struct hash<variant<Types...>>;
// template <> struct hash<monostate>;
#include <cassert>
#include <type_traits>
#include <variant>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
#ifndef TEST_HAS_NO_EXCEPTIONS
namespace std {
template <> struct hash<::MakeEmptyT> {
size_t operator()(::MakeEmptyT const &) const {
assert(false);
return 0;
}
};
}
#endif
void test_hash_variant() {
{
using V = std::variant<int, long, int>;
using H = std::hash<V>;
const V v(std::in_place_index<0>, 42);
const V v_copy = v;
V v2(std::in_place_index<0>, 100);
const V v3(std::in_place_index<2>, 42);
const H h{};
assert(h(v) == h(v));
assert(h(v) != h(v2));
assert(h(v) == h(v_copy));
{
ASSERT_SAME_TYPE(decltype(h(v)), std::size_t);
static_assert(std::is_copy_constructible<H>::value, "");
}
}
{
using V = std::variant<std::monostate, int, long, const char *>;
using H = std::hash<V>;
const char *str = "hello";
const V v0;
const V v0_other;
const V v1(42);
const V v1_other(100);
V v2(100l);
V v2_other(999l);
V v3(str);
V v3_other("not hello");
const H h{};
assert(h(v0) == h(v0));
assert(h(v0) == h(v0_other));
assert(h(v1) == h(v1));
assert(h(v1) != h(v1_other));
assert(h(v2) == h(v2));
assert(h(v2) != h(v2_other));
assert(h(v3) == h(v3));
assert(h(v3) != h(v3_other));
assert(h(v0) != h(v1));
assert(h(v0) != h(v2));
assert(h(v0) != h(v3));
assert(h(v1) != h(v2));
assert(h(v1) != h(v3));
assert(h(v2) != h(v3));
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using V = std::variant<int, MakeEmptyT>;
using H = std::hash<V>;
V v;
makeEmpty(v);
V v2;
makeEmpty(v2);
const H h{};
assert(h(v) == h(v2));
}
#endif
}
void test_hash_monostate() {
using H = std::hash<std::monostate>;
const H h{};
std::monostate m1{};
const std::monostate m2{};
assert(h(m1) == h(m1));
assert(h(m2) == h(m2));
assert(h(m1) == h(m2));
{
ASSERT_SAME_TYPE(decltype(h(m1)), std::size_t);
static_assert(std::is_copy_constructible<H>::value, "");
}
}
int main() {
test_hash_variant();
test_hash_monostate();
}

View File

@@ -0,0 +1,77 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <size_t I, class T> struct variant_alternative; // undefined
// template <size_t I, class T> struct variant_alternative<I, const T>;
// template <size_t I, class T> struct variant_alternative<I, volatile T>;
// template <size_t I, class T> struct variant_alternative<I, const volatile T>;
// template <size_t I, class T>
// using variant_alternative_t = typename variant_alternative<I, T>::type;
//
// template <size_t I, class... Types>
// struct variant_alternative<I, variant<Types...>>;
#include <memory>
#include <type_traits>
#include <variant>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
template <class V, size_t I, class E> void test() {
static_assert(
std::is_same_v<typename std::variant_alternative<I, V>::type, E>, "");
static_assert(
std::is_same_v<typename std::variant_alternative<I, const V>::type,
const E>,
"");
static_assert(
std::is_same_v<typename std::variant_alternative<I, volatile V>::type,
volatile E>,
"");
static_assert(
std::is_same_v<
typename std::variant_alternative<I, const volatile V>::type,
const volatile E>,
"");
static_assert(std::is_same_v<std::variant_alternative_t<I, V>, E>, "");
static_assert(std::is_same_v<std::variant_alternative_t<I, const V>, const E>,
"");
static_assert(
std::is_same_v<std::variant_alternative_t<I, volatile V>, volatile E>,
"");
static_assert(std::is_same_v<std::variant_alternative_t<I, const volatile V>,
const volatile E>,
"");
}
int main() {
{
using V = std::variant<int, void *, const void *, long double>;
test<V, 0, int>();
test<V, 1, void *>();
test<V, 2, const void *>();
test<V, 3, long double>();
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int, int &, int const &, int &&, long double>;
test<V, 0, int>();
test<V, 1, int &>();
test<V, 2, int const &>();
test<V, 3, int &&>();
test<V, 4, long double>();
}
#endif
}

View File

@@ -0,0 +1,44 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class T> struct variant_size; // undefined
// template <class T> struct variant_size<const T>;
// template <class T> struct variant_size<volatile T>;
// template <class T> struct variant_size<const volatile T>;
// template <class T> constexpr size_t variant_size_v
// = variant_size<T>::value;
#include <memory>
#include <type_traits>
#include <variant>
template <class V, size_t E> void test() {
static_assert(std::variant_size<V>::value == E, "");
static_assert(std::variant_size<const V>::value == E, "");
static_assert(std::variant_size<volatile V>::value == E, "");
static_assert(std::variant_size<const volatile V>::value == E, "");
static_assert(std::variant_size_v<V> == E, "");
static_assert(std::variant_size_v<const V> == E, "");
static_assert(std::variant_size_v<volatile V> == E, "");
static_assert(std::variant_size_v<const volatile V> == E, "");
static_assert(std::is_base_of<std::integral_constant<std::size_t, E>,
std::variant_size<V>>::value,
"");
};
int main() {
test<std::variant<>, 0>();
test<std::variant<void *>, 1>();
test<std::variant<long, long, void *, double>, 4>();
}

View File

@@ -0,0 +1,54 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// constexpr bool operator<(monostate, monostate) noexcept { return false; }
// constexpr bool operator>(monostate, monostate) noexcept { return false; }
// constexpr bool operator<=(monostate, monostate) noexcept { return true; }
// constexpr bool operator>=(monostate, monostate) noexcept { return true; }
// constexpr bool operator==(monostate, monostate) noexcept { return true; }
// constexpr bool operator!=(monostate, monostate) noexcept { return false; }
#include <cassert>
#include <type_traits>
#include <variant>
int main() {
using M = std::monostate;
constexpr M m1{};
constexpr M m2{};
{
static_assert((m1 < m2) == false, "");
static_assert(noexcept(m1 < m2), "");
}
{
static_assert((m1 > m2) == false, "");
static_assert(noexcept(m1 > m2), "");
}
{
static_assert((m1 <= m2) == true, "");
static_assert(noexcept(m1 <= m2), "");
}
{
static_assert((m1 >= m2) == true, "");
static_assert(noexcept(m1 >= m2), "");
}
{
static_assert((m1 == m2) == true, "");
static_assert(noexcept(m1 == m2), "");
}
{
static_assert((m1 != m2) == false, "");
static_assert(noexcept(m1 != m2), "");
}
}

View File

@@ -0,0 +1,28 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// struct monostate {};
#include <type_traits>
#include <variant>
int main() {
using M = std::monostate;
static_assert(std::is_trivially_default_constructible<M>::value, "");
static_assert(std::is_trivially_copy_constructible<M>::value, "");
static_assert(std::is_trivially_copy_assignable<M>::value, "");
static_assert(std::is_trivially_destructible<M>::value, "");
constexpr M m{};
((void)m);
}

View File

@@ -0,0 +1,227 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types>
// constexpr bool
// operator==(variant<Types...> const&, variant<Types...> const&) noexcept;
//
// template <class ...Types>
// constexpr bool
// operator!=(variant<Types...> const&, variant<Types...> const&) noexcept;
//
// template <class ...Types>
// constexpr bool
// operator<(variant<Types...> const&, variant<Types...> const&) noexcept;
//
// template <class ...Types>
// constexpr bool
// operator>(variant<Types...> const&, variant<Types...> const&) noexcept;
//
// template <class ...Types>
// constexpr bool
// operator<=(variant<Types...> const&, variant<Types...> const&) noexcept;
//
// template <class ...Types>
// constexpr bool
// operator>=(variant<Types...> const&, variant<Types...> const&) noexcept;
#include <cassert>
#include <type_traits>
#include <utility>
#include <variant>
#include "test_macros.h"
#ifndef TEST_HAS_NO_EXCEPTIONS
struct MakeEmptyT {
MakeEmptyT() = default;
MakeEmptyT(MakeEmptyT &&) { throw 42; }
MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
};
inline bool operator==(MakeEmptyT const &, MakeEmptyT const &) {
assert(false);
return false;
}
inline bool operator!=(MakeEmptyT const &, MakeEmptyT const &) {
assert(false);
return false;
}
inline bool operator<(MakeEmptyT const &, MakeEmptyT const &) {
assert(false);
return false;
}
inline bool operator<=(MakeEmptyT const &, MakeEmptyT const &) {
assert(false);
return false;
}
inline bool operator>(MakeEmptyT const &, MakeEmptyT const &) {
assert(false);
return false;
}
inline bool operator>=(MakeEmptyT const &, MakeEmptyT const &) {
assert(false);
return false;
}
template <class Variant> void makeEmpty(Variant &v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = std::move(v2);
assert(false);
} catch (...) {
assert(v.valueless_by_exception());
}
}
#endif // TEST_HAS_NO_EXCEPTIONS
void test_equality() {
{
using V = std::variant<int, long>;
constexpr V v1(42);
constexpr V v2(42);
static_assert(v1 == v2, "");
static_assert(v2 == v1, "");
static_assert(!(v1 != v2), "");
static_assert(!(v2 != v1), "");
}
{
using V = std::variant<int, long>;
constexpr V v1(42);
constexpr V v2(43);
static_assert(!(v1 == v2), "");
static_assert(!(v2 == v1), "");
static_assert(v1 != v2, "");
static_assert(v2 != v1, "");
}
{
using V = std::variant<int, long>;
constexpr V v1(42);
constexpr V v2(42l);
static_assert(!(v1 == v2), "");
static_assert(!(v2 == v1), "");
static_assert(v1 != v2, "");
static_assert(v2 != v1, "");
}
{
using V = std::variant<int, long>;
constexpr V v1(42l);
constexpr V v2(42l);
static_assert(v1 == v2, "");
static_assert(v2 == v1, "");
static_assert(!(v1 != v2), "");
static_assert(!(v2 != v1), "");
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using V = std::variant<int, MakeEmptyT>;
V v1;
V v2;
makeEmpty(v2);
assert(!(v1 == v2));
assert(!(v2 == v1));
assert(v1 != v2);
assert(v2 != v1);
}
{
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
V v2;
assert(!(v1 == v2));
assert(!(v2 == v1));
assert(v1 != v2);
assert(v2 != v1);
}
{
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
V v2;
makeEmpty(v2);
assert(v1 == v2);
assert(v2 == v1);
assert(!(v1 != v2));
assert(!(v2 != v1));
}
#endif
}
template <class Var>
constexpr bool test_less(Var const &l, Var const &r, bool expect_less,
bool expect_greater) {
return ((l < r) == expect_less) && (!(l >= r) == expect_less) &&
((l > r) == expect_greater) && (!(l <= r) == expect_greater);
}
void test_relational() {
{ // same index, same value
using V = std::variant<int, long>;
constexpr V v1(1);
constexpr V v2(1);
static_assert(test_less(v1, v2, false, false), "");
}
{ // same index, value < other_value
using V = std::variant<int, long>;
constexpr V v1(0);
constexpr V v2(1);
static_assert(test_less(v1, v2, true, false), "");
}
{ // same index, value > other_value
using V = std::variant<int, long>;
constexpr V v1(1);
constexpr V v2(0);
static_assert(test_less(v1, v2, false, true), "");
}
{ // LHS.index() < RHS.index()
using V = std::variant<int, long>;
constexpr V v1(0);
constexpr V v2(0l);
static_assert(test_less(v1, v2, true, false), "");
}
{ // LHS.index() > RHS.index()
using V = std::variant<int, long>;
constexpr V v1(0l);
constexpr V v2(0);
static_assert(test_less(v1, v2, false, true), "");
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{ // LHS.index() < RHS.index(), RHS is empty
using V = std::variant<int, MakeEmptyT>;
V v1;
V v2;
makeEmpty(v2);
assert(test_less(v1, v2, false, true));
}
{ // LHS.index() > RHS.index(), LHS is empty
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
V v2;
assert(test_less(v1, v2, true, false));
}
{ // LHS.index() == RHS.index(), LHS and RHS are empty
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
V v2;
makeEmpty(v2);
assert(test_less(v1, v2, false, false));
}
#endif
}
int main() {
test_equality();
test_relational();
}

View File

@@ -0,0 +1,21 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// constexpr size_t variant_npos = -1;
#include <variant>
int main() {
static_assert(std::variant_npos == static_cast<std::size_t>(-1), "");
}

View File

@@ -0,0 +1,232 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <class T>
// variant& operator=(T&&) noexcept(see below);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
namespace MetaHelpers {
struct Dummy {
Dummy() = default;
};
struct ThrowsCtorT {
ThrowsCtorT(int) noexcept(false) {}
ThrowsCtorT &operator=(int) noexcept { return *this; }
};
struct ThrowsAssignT {
ThrowsAssignT(int) noexcept {}
ThrowsAssignT &operator=(int) noexcept(false) { return *this; }
};
struct NoThrowT {
NoThrowT(int) noexcept {}
NoThrowT &operator=(int) noexcept { return *this; }
};
} // namespace MetaHelpers
namespace RuntimeHelpers {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct ThrowsCtorT {
int value;
ThrowsCtorT() : value(0) {}
ThrowsCtorT(int) noexcept(false) { throw 42; }
ThrowsCtorT &operator=(int v) noexcept {
value = v;
return *this;
}
};
struct ThrowsAssignT {
int value;
ThrowsAssignT() : value(0) {}
ThrowsAssignT(int v) noexcept : value(v) {}
ThrowsAssignT &operator=(int) noexcept(false) { throw 42; }
};
struct NoThrowT {
int value;
NoThrowT() : value(0) {}
NoThrowT(int v) noexcept : value(v) {}
NoThrowT &operator=(int v) noexcept {
value = v;
return *this;
}
};
#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
} // namespace RuntimeHelpers
void test_T_assignment_noexcept() {
using namespace MetaHelpers;
{
using V = std::variant<Dummy, NoThrowT>;
static_assert(std::is_nothrow_assignable<V, int>::value, "");
}
{
using V = std::variant<Dummy, ThrowsCtorT>;
static_assert(!std::is_nothrow_assignable<V, int>::value, "");
}
{
using V = std::variant<Dummy, ThrowsAssignT>;
static_assert(!std::is_nothrow_assignable<V, int>::value, "");
}
}
void test_T_assignment_sfinae() {
{
using V = std::variant<long, unsigned>;
static_assert(!std::is_assignable<V, int>::value, "ambiguous");
}
{
using V = std::variant<std::string, std::string>;
static_assert(!std::is_assignable<V, const char *>::value, "ambiguous");
}
{
using V = std::variant<std::string, void *>;
static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int, int &&>;
static_assert(!std::is_assignable<V, int>::value, "ambiguous");
}
{
using V = std::variant<int, int const &>;
static_assert(!std::is_assignable<V, int>::value, "ambiguous");
}
#endif
}
void test_T_assignment_basic() {
{
std::variant<int> v(43);
v = 42;
assert(v.index() == 0);
assert(std::get<0>(v) == 42);
}
{
std::variant<int, long> v(43l);
v = 42;
assert(v.index() == 0);
assert(std::get<0>(v) == 42);
v = 43l;
assert(v.index() == 1);
assert(std::get<1>(v) == 43);
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &, int &&, long>;
int x = 42;
V v(43l);
v = x;
assert(v.index() == 0);
assert(&std::get<0>(v) == &x);
v = std::move(x);
assert(v.index() == 1);
assert(&std::get<1>(v) == &x);
// 'long' is selected by FUN(int const&) since 'int const&' cannot bind
// to 'int&'.
int const &cx = x;
v = cx;
assert(v.index() == 2);
assert(std::get<2>(v) == 42);
}
#endif
}
void test_T_assignment_performs_construction() {
using namespace RuntimeHelpers;
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using V = std::variant<std::string, ThrowsCtorT>;
V v(std::in_place_type<std::string>, "hello");
try {
v = 42;
} catch (...) { /* ... */
}
assert(v.valueless_by_exception());
}
{
using V = std::variant<ThrowsAssignT, std::string>;
V v(std::in_place_type<std::string>, "hello");
v = 42;
assert(v.index() == 0);
assert(std::get<0>(v).value == 42);
}
#endif
}
void test_T_assignment_performs_assignment() {
using namespace RuntimeHelpers;
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using V = std::variant<ThrowsCtorT>;
V v;
v = 42;
assert(v.index() == 0);
assert(std::get<0>(v).value == 42);
}
{
using V = std::variant<ThrowsCtorT, std::string>;
V v;
v = 42;
assert(v.index() == 0);
assert(std::get<0>(v).value == 42);
}
{
using V = std::variant<ThrowsAssignT>;
V v(100);
try {
v = 42;
assert(false);
} catch (...) { /* ... */
}
assert(v.index() == 0);
assert(std::get<0>(v).value == 100);
}
{
using V = std::variant<std::string, ThrowsAssignT>;
V v(100);
try {
v = 42;
assert(false);
} catch (...) { /* ... */
}
assert(v.index() == 1);
assert(std::get<1>(v).value == 100);
}
#endif
}
int main() {
test_T_assignment_basic();
test_T_assignment_performs_construction();
test_T_assignment_performs_assignment();
test_T_assignment_noexcept();
test_T_assignment_sfinae();
}

View File

@@ -0,0 +1,396 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// variant& operator=(variant const&);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "test_macros.h"
struct NoCopy {
NoCopy(NoCopy const &) = delete;
NoCopy &operator=(NoCopy const &) = default;
};
struct NothrowCopy {
NothrowCopy(NothrowCopy const &) noexcept = default;
NothrowCopy &operator=(NothrowCopy const &) noexcept = default;
};
struct CopyOnly {
CopyOnly(CopyOnly const &) = default;
CopyOnly(CopyOnly &&) = delete;
CopyOnly &operator=(CopyOnly const &) = default;
CopyOnly &operator=(CopyOnly &&) = delete;
};
struct MoveOnly {
MoveOnly(MoveOnly const &) = delete;
MoveOnly(MoveOnly &&) = default;
MoveOnly &operator=(MoveOnly const &) = default;
};
struct MoveOnlyNT {
MoveOnlyNT(MoveOnlyNT const &) = delete;
MoveOnlyNT(MoveOnlyNT &&) {}
MoveOnlyNT &operator=(MoveOnlyNT const &) = default;
};
struct CopyAssign {
static int alive;
static int copy_construct;
static int copy_assign;
static int move_construct;
static int move_assign;
static void reset() {
copy_construct = copy_assign = move_construct = move_assign = alive = 0;
}
CopyAssign(int v) : value(v) { ++alive; }
CopyAssign(CopyAssign const &o) : value(o.value) {
++alive;
++copy_construct;
}
CopyAssign(CopyAssign &&o) : value(o.value) {
o.value = -1;
++alive;
++move_construct;
}
CopyAssign &operator=(CopyAssign const &o) {
value = o.value;
++copy_assign;
return *this;
}
CopyAssign &operator=(CopyAssign &&o) {
value = o.value;
o.value = -1;
++move_assign;
return *this;
}
~CopyAssign() { --alive; }
int value;
};
int CopyAssign::alive = 0;
int CopyAssign::copy_construct = 0;
int CopyAssign::copy_assign = 0;
int CopyAssign::move_construct = 0;
int CopyAssign::move_assign = 0;
struct CopyMaybeThrows {
CopyMaybeThrows(CopyMaybeThrows const &);
CopyMaybeThrows &operator=(CopyMaybeThrows const &);
};
struct CopyDoesThrow {
CopyDoesThrow(CopyDoesThrow const &) noexcept(false);
CopyDoesThrow &operator=(CopyDoesThrow const &) noexcept(false);
};
#ifndef TEST_HAS_NO_EXCEPTIONS
struct CopyThrows {
CopyThrows() = default;
CopyThrows(CopyThrows const &) { throw 42; }
CopyThrows &operator=(CopyThrows const &) { throw 42; }
};
struct MoveThrows {
static int alive;
MoveThrows() { ++alive; }
MoveThrows(MoveThrows const &) { ++alive; }
MoveThrows(MoveThrows &&) { throw 42; }
MoveThrows &operator=(MoveThrows const &) { return *this; }
MoveThrows &operator=(MoveThrows &&) { throw 42; }
~MoveThrows() { --alive; }
};
int MoveThrows::alive = 0;
struct MakeEmptyT {
static int alive;
MakeEmptyT() { ++alive; }
MakeEmptyT(MakeEmptyT const &) {
++alive;
// Don't throw from the copy constructor since variant's assignment
// operator performs a copy before committing to the assignment.
}
MakeEmptyT(MakeEmptyT &&) { throw 42; }
MakeEmptyT &operator=(MakeEmptyT const &) { throw 42; }
MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
~MakeEmptyT() { --alive; }
};
int MakeEmptyT::alive = 0;
template <class Variant> void makeEmpty(Variant &v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = v2;
assert(false);
} catch (...) {
assert(v.valueless_by_exception());
}
}
#endif // TEST_HAS_NO_EXCEPTIONS
void test_copy_assignment_not_noexcept() {
{
using V = std::variant<CopyMaybeThrows>;
static_assert(!std::is_nothrow_copy_assignable<V>::value, "");
}
{
using V = std::variant<int, CopyDoesThrow>;
static_assert(!std::is_nothrow_copy_assignable<V>::value, "");
}
}
void test_copy_assignment_sfinae() {
{
using V = std::variant<int, long>;
static_assert(std::is_copy_assignable<V>::value, "");
}
{
// variant only provides copy assignment when beth the copy and move
// constructors are well formed
using V = std::variant<int, CopyOnly>;
static_assert(!std::is_copy_assignable<V>::value, "");
}
{
using V = std::variant<int, NoCopy>;
static_assert(!std::is_copy_assignable<V>::value, "");
}
{
using V = std::variant<int, MoveOnly>;
static_assert(!std::is_copy_assignable<V>::value, "");
}
{
using V = std::variant<int, MoveOnlyNT>;
static_assert(!std::is_copy_assignable<V>::value, "");
}
}
void test_copy_assignment_empty_empty() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, long, MET>;
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_index<0>);
makeEmpty(v2);
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
#endif
}
void test_copy_assignment_non_empty_empty() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, MET>;
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>);
makeEmpty(v2);
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
{
using V = std::variant<int, MET, std::string>;
V v1(std::in_place_index<2>, "hello");
V v2(std::in_place_index<0>);
makeEmpty(v2);
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
#endif
}
void test_copy_assignment_empty_non_empty() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, MET>;
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_index<0>, 42);
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 0);
assert(std::get<0>(v1) == 42);
}
{
using V = std::variant<int, MET, std::string>;
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_type<std::string>, "hello");
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
}
#endif
}
void test_copy_assignment_same_index() {
{
using V = std::variant<int>;
V v1(43);
V v2(42);
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 0);
assert(std::get<0>(v1) == 42);
}
{
using V = std::variant<int, long, unsigned>;
V v1(43l);
V v2(42l);
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1) == 42);
}
{
using V = std::variant<int, CopyAssign, unsigned>;
V v1(std::in_place_type<CopyAssign>, 43);
V v2(std::in_place_type<CopyAssign>, 42);
CopyAssign::reset();
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1).value == 42);
assert(CopyAssign::copy_construct == 0);
assert(CopyAssign::move_construct == 0);
assert(CopyAssign::copy_assign == 1);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, MET, std::string>;
V v1(std::in_place_type<MET>);
MET &mref = std::get<1>(v1);
V v2(std::in_place_type<MET>);
try {
v1 = v2;
assert(false);
} catch (...) {
}
assert(v1.index() == 1);
assert(&std::get<1>(v1) == &mref);
}
#endif
}
void test_copy_assignment_different_index() {
{
using V = std::variant<int, long, unsigned>;
V v1(43);
V v2(42l);
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1) == 42);
}
{
using V = std::variant<int, CopyAssign, unsigned>;
CopyAssign::reset();
V v1(std::in_place_type<unsigned>, 43);
V v2(std::in_place_type<CopyAssign>, 42);
assert(CopyAssign::copy_construct == 0);
assert(CopyAssign::move_construct == 0);
assert(CopyAssign::alive == 1);
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1).value == 42);
assert(CopyAssign::alive == 2);
assert(CopyAssign::copy_construct == 1);
assert(CopyAssign::move_construct == 1);
assert(CopyAssign::copy_assign == 0);
}
#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>);
try {
v1 = v2;
assert(false);
} catch (...) { /* ... */
}
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
}
{
// 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());
assert(v2.index() == 1);
assert(MoveThrows::alive == 1);
}
{
using V = std::variant<int, CopyThrows, std::string>;
V v1(std::in_place_type<CopyThrows>);
V v2(std::in_place_type<std::string>, "hello");
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
assert(v2.index() == 2);
assert(std::get<2>(v2) == "hello");
}
{
using V = std::variant<int, MoveThrows, std::string>;
V v1(std::in_place_type<MoveThrows>);
V v2(std::in_place_type<std::string>, "hello");
V &vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
assert(v2.index() == 2);
assert(std::get<2>(v2) == "hello");
}
#endif
}
int main() {
test_copy_assignment_empty_empty();
test_copy_assignment_non_empty_empty();
test_copy_assignment_empty_non_empty();
test_copy_assignment_same_index();
test_copy_assignment_different_index();
test_copy_assignment_sfinae();
test_copy_assignment_not_noexcept();
}

View File

@@ -0,0 +1,319 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// variant& operator=(variant&&) noexcept(see below);
#include <cassert>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
struct NoCopy {
NoCopy(NoCopy const &) = delete;
NoCopy &operator=(NoCopy const &) = default;
};
struct CopyOnly {
CopyOnly(CopyOnly const &) = default;
CopyOnly(CopyOnly &&) = delete;
CopyOnly &operator=(CopyOnly const &) = default;
CopyOnly &operator=(CopyOnly &&) = delete;
};
struct MoveOnly {
MoveOnly(MoveOnly const &) = delete;
MoveOnly(MoveOnly &&) = default;
MoveOnly &operator=(MoveOnly const &) = delete;
MoveOnly &operator=(MoveOnly &&) = default;
};
struct MoveOnlyNT {
MoveOnlyNT(MoveOnlyNT const &) = delete;
MoveOnlyNT(MoveOnlyNT &&) {}
MoveOnlyNT &operator=(MoveOnlyNT const &) = delete;
MoveOnlyNT &operator=(MoveOnlyNT &&) = default;
};
struct MoveOnlyOddNothrow {
MoveOnlyOddNothrow(MoveOnlyOddNothrow &&) noexcept(false) {}
MoveOnlyOddNothrow(MoveOnlyOddNothrow const &) = delete;
MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow &&) noexcept = default;
MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow const &) = delete;
};
struct MoveAssignOnly {
MoveAssignOnly(MoveAssignOnly &&) = delete;
MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
};
struct MoveAssign {
static int move_construct;
static int move_assign;
static void reset() { move_construct = move_assign = 0; }
MoveAssign(int v) : value(v) {}
MoveAssign(MoveAssign &&o) : value(o.value) {
++move_construct;
o.value = -1;
}
MoveAssign &operator=(MoveAssign &&o) {
value = o.value;
++move_assign;
o.value = -1;
return *this;
}
int value;
};
int MoveAssign::move_construct = 0;
int MoveAssign::move_assign = 0;
void test_move_assignment_noexcept() {
{
using V = std::variant<int>;
static_assert(std::is_nothrow_move_assignable<V>::value, "");
}
{
using V = std::variant<MoveOnly>;
static_assert(std::is_nothrow_move_assignable<V>::value, "");
}
{
using V = std::variant<int, long>;
static_assert(std::is_nothrow_move_assignable<V>::value, "");
}
{
using V = std::variant<int, MoveOnly>;
static_assert(std::is_nothrow_move_assignable<V>::value, "");
}
{
using V = std::variant<MoveOnlyNT>;
static_assert(!std::is_nothrow_move_assignable<V>::value, "");
}
{
using V = std::variant<MoveOnlyOddNothrow>;
static_assert(!std::is_nothrow_move_assignable<V>::value, "");
}
}
void test_move_assignment_sfinae() {
{
using V = std::variant<int, long>;
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, "");
}
{
using V = std::variant<int, NoCopy>;
static_assert(!std::is_move_assignable<V>::value, "");
}
{
using V = std::variant<int, MoveOnly>;
static_assert(std::is_move_assignable<V>::value, "");
}
{
using V = std::variant<int, MoveOnlyNT>;
static_assert(std::is_move_assignable<V>::value, "");
}
{
// variant only provides move assignment when the types also provide
// a move constructor.
using V = std::variant<int, MoveAssignOnly>;
static_assert(!std::is_move_assignable<V>::value, "");
}
}
void test_move_assignment_empty_empty() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, long, MET>;
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_index<0>);
makeEmpty(v2);
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
#endif
}
void test_move_assignment_non_empty_empty() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, MET>;
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>);
makeEmpty(v2);
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
{
using V = std::variant<int, MET, std::string>;
V v1(std::in_place_index<2>, "hello");
V v2(std::in_place_index<0>);
makeEmpty(v2);
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
#endif
}
void test_move_assignment_empty_non_empty() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, MET>;
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_index<0>, 42);
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 0);
assert(std::get<0>(v1) == 42);
}
{
using V = std::variant<int, MET, std::string>;
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_type<std::string>, "hello");
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
}
#endif
}
void test_move_assignment_same_index() {
{
using V = std::variant<int>;
V v1(43);
V v2(42);
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 0);
assert(std::get<0>(v1) == 42);
}
{
using V = std::variant<int, long, unsigned>;
V v1(43l);
V v2(42l);
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1) == 42);
}
{
using V = std::variant<int, MoveAssign, unsigned>;
V v1(std::in_place_type<MoveAssign>, 43);
V v2(std::in_place_type<MoveAssign>, 42);
MoveAssign::reset();
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1).value == 42);
assert(MoveAssign::move_construct == 0);
assert(MoveAssign::move_assign == 1);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, MET, std::string>;
V v1(std::in_place_type<MET>);
MET &mref = std::get<1>(v1);
V v2(std::in_place_type<MET>);
try {
v1 = std::move(v2);
assert(false);
} catch (...) {
}
assert(v1.index() == 1);
assert(&std::get<1>(v1) == &mref);
}
#endif
}
void test_move_assignment_different_index() {
{
using V = std::variant<int, long, unsigned>;
V v1(43);
V v2(42l);
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1) == 42);
}
{
using V = std::variant<int, MoveAssign, unsigned>;
V v1(std::in_place_type<unsigned>, 43);
V v2(std::in_place_type<MoveAssign>, 42);
MoveAssign::reset();
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1).value == 42);
assert(MoveAssign::move_construct == 1);
assert(MoveAssign::move_assign == 0);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
using MET = MakeEmptyT;
{
using V = std::variant<int, MET, std::string>;
V v1(std::in_place_type<int>);
V v2(std::in_place_type<MET>);
try {
v1 = std::move(v2);
assert(false);
} catch (...) {
}
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
{
using V = std::variant<int, MET, std::string>;
V v1(std::in_place_type<MET>);
V v2(std::in_place_type<std::string>, "hello");
V &vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
}
#endif
}
int main() {
test_move_assignment_empty_empty();
test_move_assignment_non_empty_empty();
test_move_assignment_empty_non_empty();
test_move_assignment_same_index();
test_move_assignment_different_index();
test_move_assignment_sfinae();
test_move_assignment_noexcept();
}

View File

@@ -0,0 +1,112 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <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 "test_convertible.hpp"
#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) {}
};
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, unsigned>;
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");
}
#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, int const &>;
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, "");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int const &, 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<int const &, 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
}
int main() {
test_T_ctor_basic();
test_T_ctor_noexcept();
test_T_ctor_sfinae();
}

View File

@@ -0,0 +1,137 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// variant(variant const&);
#include <cassert>
#include <type_traits>
#include <variant>
#include "test_macros.h"
struct NonT {
NonT(int v) : value(v) {}
NonT(NonT const &o) : value(o.value) {}
int value;
};
static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");
struct NoCopy {
NoCopy(NoCopy const &) = delete;
};
struct MoveOnly {
MoveOnly(MoveOnly const &) = delete;
MoveOnly(MoveOnly &&) = default;
};
struct MoveOnlyNT {
MoveOnlyNT(MoveOnlyNT const &) = delete;
MoveOnlyNT(MoveOnlyNT &&) {}
};
#ifndef TEST_HAS_NO_EXCEPTIONS
struct MakeEmptyT {
static int alive;
MakeEmptyT() { ++alive; }
MakeEmptyT(MakeEmptyT const &) {
++alive;
// Don't throw from the copy constructor since variant's assignment
// operator performs a copy before committing to the assignment.
}
MakeEmptyT(MakeEmptyT &&) { throw 42; }
MakeEmptyT &operator=(MakeEmptyT const &) { throw 42; }
MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
~MakeEmptyT() { --alive; }
};
int MakeEmptyT::alive = 0;
template <class Variant> void makeEmpty(Variant &v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = v2;
assert(false);
} catch (...) {
assert(v.valueless_by_exception());
}
}
#endif // TEST_HAS_NO_EXCEPTIONS
void test_copy_ctor_sfinae() {
{
using V = std::variant<int, long>;
static_assert(std::is_copy_constructible<V>::value, "");
}
{
using V = std::variant<int, NoCopy>;
static_assert(!std::is_copy_constructible<V>::value, "");
}
{
using V = std::variant<int, MoveOnly>;
static_assert(!std::is_copy_constructible<V>::value, "");
}
{
using V = std::variant<int, MoveOnlyNT>;
static_assert(!std::is_copy_constructible<V>::value, "");
}
}
void test_copy_ctor_basic() {
{
std::variant<int> v(std::in_place_index<0>, 42);
std::variant<int> v2 = v;
assert(v2.index() == 0);
assert(std::get<0>(v2) == 42);
}
{
std::variant<int, long> v(std::in_place_index<1>, 42);
std::variant<int, long> v2 = v;
assert(v2.index() == 1);
assert(std::get<1>(v2) == 42);
}
{
std::variant<NonT> v(std::in_place_index<0>, 42);
assert(v.index() == 0);
std::variant<NonT> v2(v);
assert(v2.index() == 0);
assert(std::get<0>(v2).value == 42);
}
{
std::variant<int, NonT> v(std::in_place_index<1>, 42);
assert(v.index() == 1);
std::variant<int, NonT> v2(v);
assert(v2.index() == 1);
assert(std::get<1>(v2).value == 42);
}
}
void test_copy_ctor_valueless_by_exception() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
V const &cv1 = v1;
V v(cv1);
assert(v.valueless_by_exception());
#endif
}
int main() {
test_copy_ctor_basic();
test_copy_ctor_valueless_by_exception();
test_copy_ctor_sfinae();
}

View File

@@ -0,0 +1,112 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// constexpr variant() noexcept(see below);
#include <cassert>
#include <type_traits>
#include <variant>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
struct NonDefaultConstructible {
NonDefaultConstructible(int) {}
};
struct NotNoexcept {
NotNoexcept() noexcept(false) {}
};
#ifndef TEST_HAS_NO_EXCEPTIONS
struct DefaultCtorThrows {
DefaultCtorThrows() { throw 42; }
};
#endif
void test_default_ctor_sfinae() {
{
using V = std::variant<std::monostate, int>;
static_assert(std::is_default_constructible<V>::value, "");
}
{
using V = std::variant<NonDefaultConstructible, int>;
static_assert(!std::is_default_constructible<V>::value, "");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int &, int>;
static_assert(!std::is_default_constructible<V>::value, "");
}
#endif
}
void test_default_ctor_noexcept() {
{
using V = std::variant<int>;
static_assert(std::is_nothrow_default_constructible<V>::value, "");
}
{
using V = std::variant<NotNoexcept>;
static_assert(!std::is_nothrow_default_constructible<V>::value, "");
}
}
void test_default_ctor_throws() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using V = std::variant<DefaultCtorThrows, int>;
try {
V v;
assert(false);
} catch (int const &ex) {
assert(ex == 42);
} catch (...) {
assert(false);
}
#endif
}
void test_default_ctor_basic() {
{
std::variant<int> v;
assert(v.index() == 0);
assert(std::get<0>(v) == 0);
}
{
std::variant<int, long> v;
assert(v.index() == 0);
assert(std::get<0>(v) == 0);
}
{
using V = std::variant<int, long>;
constexpr V v;
static_assert(v.index() == 0, "");
static_assert(std::get<0>(v) == 0, "");
}
{
using V = std::variant<int, long>;
constexpr V v;
static_assert(v.index() == 0, "");
static_assert(std::get<0>(v) == 0, "");
}
}
int main() {
test_default_ctor_basic();
test_default_ctor_sfinae();
test_default_ctor_noexcept();
test_default_ctor_throws();
}

View File

@@ -0,0 +1,103 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <size_t I, class ...Args>
// constexpr explicit variant(in_place_index_t<I>, Args&&...);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "test_convertible.hpp"
#include "test_macros.h"
void test_ctor_sfinae() {
{
using V = std::variant<int>;
static_assert(
std::is_constructible<V, std::in_place_index_t<0>, int>::value, "");
static_assert(!test_convertible<V, std::in_place_index_t<0>, int>(), "");
}
{
using V = std::variant<int, long, long long>;
static_assert(
std::is_constructible<V, std::in_place_index_t<1>, int>::value, "");
static_assert(!test_convertible<V, std::in_place_index_t<1>, int>(), "");
}
{
using V = std::variant<int, long, int *>;
static_assert(
std::is_constructible<V, std::in_place_index_t<2>, int *>::value, "");
static_assert(!test_convertible<V, std::in_place_index_t<2>, int *>(), "");
}
{ // args not convertible to type
using V = std::variant<int, long, int *>;
static_assert(
!std::is_constructible<V, std::in_place_index_t<0>, int *>::value, "");
static_assert(!test_convertible<V, std::in_place_index_t<0>, int *>(), "");
}
{ // index not in variant
using V = std::variant<int, long, int *>;
static_assert(
!std::is_constructible<V, std::in_place_index_t<3>, int>::value, "");
static_assert(!test_convertible<V, std::in_place_index_t<3>, int>(), "");
}
}
void test_ctor_basic() {
{
constexpr std::variant<int> v(std::in_place_index<0>, 42);
static_assert(v.index() == 0, "");
static_assert(std::get<0>(v) == 42, "");
}
{
constexpr std::variant<int, long, long> v(std::in_place_index<1>, 42);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v) == 42, "");
}
{
constexpr std::variant<int, const int, long> v(std::in_place_index<1>, 42);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v) == 42, "");
}
{
using V = std::variant<const int, volatile int, int>;
int x = 42;
V v(std::in_place_index<0>, x);
assert(v.index() == 0);
assert(std::get<0>(v) == x);
}
{
using V = std::variant<const int, volatile int, int>;
int x = 42;
V v(std::in_place_index<1>, x);
assert(v.index() == 1);
assert(std::get<1>(v) == x);
}
{
using V = std::variant<const int, volatile int, int>;
int x = 42;
V v(std::in_place_index<2>, x);
assert(v.index() == 2);
assert(std::get<2>(v) == x);
}
}
int main() {
test_ctor_basic();
test_ctor_sfinae();
}

View File

@@ -0,0 +1,103 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <size_t I, class Up, class ...Args>
// constexpr explicit
// variant(in_place_index_t<I>, initializer_list<Up>, Args&&...);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "test_convertible.hpp"
#include "test_macros.h"
struct InitList {
std::size_t size;
constexpr InitList(std::initializer_list<int> il) : size(il.size()) {}
};
struct InitListArg {
std::size_t size;
int value;
constexpr InitListArg(std::initializer_list<int> il, int v)
: size(il.size()), value(v) {}
};
void test_ctor_sfinae() {
using IL = std::initializer_list<int>;
{ // just init list
using V = std::variant<InitList, InitListArg, int>;
static_assert(std::is_constructible<V, std::in_place_index_t<0>, IL>::value,
"");
static_assert(!test_convertible<V, std::in_place_index_t<0>, IL>(), "");
}
{ // too many arguments
using V = std::variant<InitList, InitListArg, int>;
static_assert(
!std::is_constructible<V, std::in_place_index_t<0>, IL, int>::value,
"");
static_assert(!test_convertible<V, std::in_place_index_t<0>, IL, int>(),
"");
}
{ // too few arguments
using V = std::variant<InitList, InitListArg, int>;
static_assert(
!std::is_constructible<V, std::in_place_index_t<1>, IL>::value, "");
static_assert(!test_convertible<V, std::in_place_index_t<1>, IL>(), "");
}
{ // init list and arguments
using V = std::variant<InitList, InitListArg, int>;
static_assert(
std::is_constructible<V, std::in_place_index_t<1>, IL, int>::value, "");
static_assert(!test_convertible<V, std::in_place_index_t<1>, IL, int>(),
"");
}
{ // not constructible from arguments
using V = std::variant<InitList, InitListArg, int>;
static_assert(
!std::is_constructible<V, std::in_place_index_t<2>, IL>::value, "");
static_assert(!test_convertible<V, std::in_place_index_t<2>, IL>(), "");
}
}
void test_ctor_basic() {
{
constexpr std::variant<InitList, InitListArg, InitList> v(
std::in_place_index<0>, {1, 2, 3});
static_assert(v.index() == 0, "");
static_assert(std::get<0>(v).size == 3, "");
}
{
constexpr std::variant<InitList, InitListArg, InitList> v(
std::in_place_index<2>, {1, 2, 3});
static_assert(v.index() == 2, "");
static_assert(std::get<2>(v).size == 3, "");
}
{
constexpr std::variant<InitList, InitListArg, InitListArg> v(
std::in_place_index<1>, {1, 2, 3, 4}, 42);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v).size == 4, "");
static_assert(std::get<1>(v).value == 42, "");
}
}
int main() {
test_ctor_basic();
test_ctor_sfinae();
}

View File

@@ -0,0 +1,113 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <class Tp, class ...Args>
// constexpr explicit variant(in_place_type_t<Tp>, Args&&...);
#include <cassert>
#include <type_traits>
#include <variant>
#include "test_convertible.hpp"
#include "test_macros.h"
void test_ctor_sfinae() {
{
using V = std::variant<int>;
static_assert(
std::is_constructible<V, std::in_place_type_t<int>, int>::value, "");
static_assert(!test_convertible<V, std::in_place_type_t<int>, int>(), "");
}
{
using V = std::variant<int, long, long long>;
static_assert(
std::is_constructible<V, std::in_place_type_t<long>, int>::value, "");
static_assert(!test_convertible<V, std::in_place_type_t<long>, int>(), "");
}
{
using V = std::variant<int, long, int *>;
static_assert(
std::is_constructible<V, std::in_place_type_t<int *>, int *>::value,
"");
static_assert(!test_convertible<V, std::in_place_type_t<int *>, int *>(),
"");
}
{ // duplicate type
using V = std::variant<int, long, int>;
static_assert(
!std::is_constructible<V, std::in_place_type_t<int>, int>::value, "");
static_assert(!test_convertible<V, std::in_place_type_t<int>, int>(), "");
}
{ // args not convertible to type
using V = std::variant<int, long, int *>;
static_assert(
!std::is_constructible<V, std::in_place_type_t<int>, int *>::value, "");
static_assert(!test_convertible<V, std::in_place_type_t<int>, int *>(), "");
}
{ // type not in variant
using V = std::variant<int, long, int *>;
static_assert(
!std::is_constructible<V, std::in_place_type_t<long long>, int>::value,
"");
static_assert(!test_convertible<V, std::in_place_type_t<long long>, int>(),
"");
}
}
void test_ctor_basic() {
{
constexpr std::variant<int> v(std::in_place_type<int>, 42);
static_assert(v.index() == 0, "");
static_assert(std::get<0>(v) == 42, "");
}
{
constexpr std::variant<int, long> v(std::in_place_type<long>, 42);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v) == 42, "");
}
{
constexpr std::variant<int, const int, long> v(
std::in_place_type<const int>, 42);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v) == 42, "");
}
{
using V = std::variant<const int, volatile int, int>;
int x = 42;
V v(std::in_place_type<const int>, x);
assert(v.index() == 0);
assert(std::get<0>(v) == x);
}
{
using V = std::variant<const int, volatile int, int>;
int x = 42;
V v(std::in_place_type<volatile int>, x);
assert(v.index() == 1);
assert(std::get<1>(v) == x);
}
{
using V = std::variant<const int, volatile int, int>;
int x = 42;
V v(std::in_place_type<int>, x);
assert(v.index() == 2);
assert(std::get<2>(v) == x);
}
}
int main() {
test_ctor_basic();
test_ctor_sfinae();
}

View File

@@ -0,0 +1,110 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <class Tp, class Up, class ...Args>
// constexpr explicit
// variant(in_place_type_t<Tp>, initializer_list<Up>, Args&&...);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "test_convertible.hpp"
#include "test_macros.h"
struct InitList {
std::size_t size;
constexpr InitList(std::initializer_list<int> il) : size(il.size()) {}
};
struct InitListArg {
std::size_t size;
int value;
constexpr InitListArg(std::initializer_list<int> il, int v)
: size(il.size()), value(v) {}
};
void test_ctor_sfinae() {
using IL = std::initializer_list<int>;
{ // just init list
using V = std::variant<InitList, InitListArg, int>;
static_assert(
std::is_constructible<V, std::in_place_type_t<InitList>, IL>::value,
"");
static_assert(!test_convertible<V, std::in_place_type_t<InitList>, IL>(),
"");
}
{ // too many arguments
using V = std::variant<InitList, InitListArg, int>;
static_assert(!std::is_constructible<V, std::in_place_type_t<InitList>, IL,
int>::value,
"");
static_assert(
!test_convertible<V, std::in_place_type_t<InitList>, IL, int>(), "");
}
{ // too few arguments
using V = std::variant<InitList, InitListArg, int>;
static_assert(
!std::is_constructible<V, std::in_place_type_t<InitListArg>, IL>::value,
"");
static_assert(!test_convertible<V, std::in_place_type_t<InitListArg>, IL>(),
"");
}
{ // init list and arguments
using V = std::variant<InitList, InitListArg, int>;
static_assert(std::is_constructible<V, std::in_place_type_t<InitListArg>,
IL, int>::value,
"");
static_assert(
!test_convertible<V, std::in_place_type_t<InitListArg>, IL, int>(), "");
}
{ // not constructible from arguments
using V = std::variant<InitList, InitListArg, int>;
static_assert(
!std::is_constructible<V, std::in_place_type_t<int>, IL>::value, "");
static_assert(!test_convertible<V, std::in_place_type_t<int>, IL>(), "");
}
{ // duplicate types in variant
using V = std::variant<InitListArg, InitListArg, int>;
static_assert(!std::is_constructible<V, std::in_place_type_t<InitListArg>,
IL, int>::value,
"");
static_assert(
!test_convertible<V, std::in_place_type_t<InitListArg>, IL, int>(), "");
}
}
void test_ctor_basic() {
{
constexpr std::variant<InitList, InitListArg> v(
std::in_place_type<InitList>, {1, 2, 3});
static_assert(v.index() == 0, "");
static_assert(std::get<0>(v).size == 3, "");
}
{
constexpr std::variant<InitList, InitListArg> v(
std::in_place_type<InitListArg>, {1, 2, 3, 4}, 42);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v).size == 4, "");
static_assert(std::get<1>(v).value == 42, "");
}
}
int main() {
test_ctor_basic();
test_ctor_sfinae();
}

View File

@@ -0,0 +1,174 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// variant(variant&&) noexcept(see below);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "test_macros.h"
struct ThrowsMove {
ThrowsMove(ThrowsMove &&) noexcept(false) {}
};
struct NoCopy {
NoCopy(NoCopy const &) = delete;
};
struct MoveOnly {
int value;
MoveOnly(int v) : value(v) {}
MoveOnly(MoveOnly const &) = delete;
MoveOnly(MoveOnly &&) = default;
};
struct MoveOnlyNT {
int value;
MoveOnlyNT(int v) : value(v) {}
MoveOnlyNT(MoveOnlyNT const &) = delete;
MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; }
};
#ifndef TEST_HAS_NO_EXCEPTIONS
struct MakeEmptyT {
static int alive;
MakeEmptyT() { ++alive; }
MakeEmptyT(MakeEmptyT const &) {
++alive;
// Don't throw from the copy constructor since variant's assignment
// operator performs a copy before committing to the assignment.
}
MakeEmptyT(MakeEmptyT &&) { throw 42; }
MakeEmptyT &operator=(MakeEmptyT const &) { throw 42; }
MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
~MakeEmptyT() { --alive; }
};
int MakeEmptyT::alive = 0;
template <class Variant> void makeEmpty(Variant &v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = v2;
assert(false);
} catch (...) {
assert(v.valueless_by_exception());
}
}
#endif // TEST_HAS_NO_EXCEPTIONS
void test_move_noexcept() {
{
using V = std::variant<int, long>;
static_assert(std::is_nothrow_move_constructible<V>::value, "");
}
{
using V = std::variant<int, MoveOnly>;
static_assert(std::is_nothrow_move_constructible<V>::value, "");
}
{
using V = std::variant<int, MoveOnlyNT>;
static_assert(!std::is_nothrow_move_constructible<V>::value, "");
}
{
using V = std::variant<int, ThrowsMove>;
static_assert(!std::is_nothrow_move_constructible<V>::value, "");
}
}
void test_move_ctor_sfinae() {
{
using V = std::variant<int, long>;
static_assert(std::is_move_constructible<V>::value, "");
}
{
using V = std::variant<int, MoveOnly>;
static_assert(std::is_move_constructible<V>::value, "");
}
{
using V = std::variant<int, MoveOnlyNT>;
static_assert(std::is_move_constructible<V>::value, "");
}
{
using V = std::variant<int, NoCopy>;
static_assert(!std::is_move_constructible<V>::value, "");
}
}
void test_move_ctor_basic() {
{
std::variant<int> v(std::in_place_index<0>, 42);
std::variant<int> v2 = std::move(v);
assert(v2.index() == 0);
assert(std::get<0>(v2) == 42);
}
{
std::variant<int, long> v(std::in_place_index<1>, 42);
std::variant<int, long> v2 = std::move(v);
assert(v2.index() == 1);
assert(std::get<1>(v2) == 42);
}
{
std::variant<MoveOnly> v(std::in_place_index<0>, 42);
assert(v.index() == 0);
std::variant<MoveOnly> v2(std::move(v));
assert(v2.index() == 0);
assert(std::get<0>(v2).value == 42);
}
{
std::variant<int, MoveOnly> v(std::in_place_index<1>, 42);
assert(v.index() == 1);
std::variant<int, MoveOnly> v2(std::move(v));
assert(v2.index() == 1);
assert(std::get<1>(v2).value == 42);
}
{
std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42);
assert(v.index() == 0);
std::variant<MoveOnlyNT> v2(std::move(v));
assert(v2.index() == 0);
assert(std::get<0>(v).value == -1);
assert(std::get<0>(v2).value == 42);
}
{
std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42);
assert(v.index() == 1);
std::variant<int, MoveOnlyNT> v2(std::move(v));
assert(v2.index() == 1);
assert(std::get<1>(v).value == -1);
assert(std::get<1>(v2).value == 42);
}
}
void test_move_ctor_valueless_by_exception() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
V v(std::move(v1));
assert(v.valueless_by_exception());
#endif
}
int main() {
test_move_ctor_basic();
test_move_ctor_valueless_by_exception();
test_move_noexcept();
test_move_ctor_sfinae();
}

View File

@@ -0,0 +1,75 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// ~variant();
#include <cassert>
#include <type_traits>
#include <variant>
#include "test_macros.h"
struct NonTDtor {
static int count;
NonTDtor() = default;
~NonTDtor() { ++count; }
};
int NonTDtor::count = 0;
static_assert(!std::is_trivially_destructible<NonTDtor>::value, "");
struct NonTDtor1 {
static int count;
NonTDtor1() = default;
~NonTDtor1() { ++count; }
};
int NonTDtor1::count = 0;
static_assert(!std::is_trivially_destructible<NonTDtor1>::value, "");
struct TDtor {
TDtor(TDtor const &) {} // non-trivial copy
~TDtor() = default;
};
static_assert(!std::is_trivially_copy_constructible<TDtor>::value, "");
static_assert(std::is_trivially_destructible<TDtor>::value, "");
int main() {
{
using V = std::variant<int, long, TDtor>;
static_assert(std::is_trivially_destructible<V>::value, "");
}
{
using V = std::variant<NonTDtor, int, NonTDtor1>;
static_assert(!std::is_trivially_destructible<V>::value, "");
{
V v(std::in_place_index<0>);
assert(NonTDtor::count == 0);
assert(NonTDtor1::count == 0);
}
assert(NonTDtor::count == 1);
assert(NonTDtor1::count == 0);
NonTDtor::count = 0;
{ V v(std::in_place_index<1>); }
assert(NonTDtor::count == 0);
assert(NonTDtor1::count == 0);
{
V v(std::in_place_index<2>);
assert(NonTDtor::count == 0);
assert(NonTDtor1::count == 0);
}
assert(NonTDtor::count == 0);
assert(NonTDtor1::count == 1);
}
}

View File

@@ -0,0 +1,137 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <size_t I, class ...Args> void emplace(Args&&... args);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "archetypes.hpp"
#include "test_convertible.hpp"
#include "test_macros.h"
#include "variant_test_helpers.hpp"
template <class Var, size_t I, class... Args>
constexpr auto test_emplace_exists_imp(int) -> decltype(
std::declval<Var>().template emplace<I>(std::declval<Args>()...), true) {
return true;
}
template <class, size_t, class...>
constexpr auto test_emplace_exists_imp(long) -> bool {
return false;
}
template <class Var, size_t I, class... Args> constexpr bool emplace_exists() {
return test_emplace_exists_imp<Var, I, Args...>(0);
}
void test_emplace_sfinae() {
{
using V = std::variant<int, void *, const void *, TestTypes::NoCtors>;
static_assert(emplace_exists<V, 0>(), "");
static_assert(emplace_exists<V, 0, int>(), "");
static_assert(!emplace_exists<V, 0, decltype(nullptr)>(),
"cannot construct");
static_assert(emplace_exists<V, 1, decltype(nullptr)>(), "");
static_assert(emplace_exists<V, 1, int *>(), "");
static_assert(!emplace_exists<V, 1, const int *>(), "");
static_assert(!emplace_exists<V, 1, int>(), "cannot construct");
static_assert(emplace_exists<V, 2, const int *>(), "");
static_assert(emplace_exists<V, 2, int *>(), "");
static_assert(!emplace_exists<V, 3>(), "cannot construct");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int, int &, int const &, int &&, TestTypes::NoCtors>;
static_assert(emplace_exists<V, 0>(), "");
static_assert(emplace_exists<V, 0, int>(), "");
static_assert(emplace_exists<V, 0, long long>(), "");
static_assert(!emplace_exists<V, 0, int, int>(), "too many args");
static_assert(emplace_exists<V, 1, int &>(), "");
static_assert(!emplace_exists<V, 1>(), "cannot default construct ref");
static_assert(!emplace_exists<V, 1, int const &>(), "cannot bind ref");
static_assert(!emplace_exists<V, 1, int &&>(), "cannot bind ref");
static_assert(emplace_exists<V, 2, int &>(), "");
static_assert(emplace_exists<V, 2, const int &>(), "");
static_assert(emplace_exists<V, 2, int &&>(), "");
static_assert(!emplace_exists<V, 2, void *>(),
"not constructible from void*");
static_assert(emplace_exists<V, 3, int>(), "");
static_assert(!emplace_exists<V, 3, int &>(), "cannot bind ref");
static_assert(!emplace_exists<V, 3, int const &>(), "cannot bind ref");
static_assert(!emplace_exists<V, 3, int const &&>(), "cannot bind ref");
static_assert(!emplace_exists<V, 4>(), "no ctors");
}
#endif
}
void test_basic() {
{
using V = std::variant<int>;
V v(42);
v.emplace<0>();
assert(std::get<0>(v) == 0);
v.emplace<0>(42);
assert(std::get<0>(v) == 42);
}
{
using V =
std::variant<int, long, const void *, TestTypes::NoCtors, std::string>;
const int x = 100;
V v(std::in_place_index<0>, -1);
// default emplace a value
v.emplace<1>();
assert(std::get<1>(v) == 0);
v.emplace<2>(&x);
assert(std::get<2>(v) == &x);
// emplace with multiple args
v.emplace<4>(3, 'a');
assert(std::get<4>(v) == "aaa");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int, long, int const &, int &&, TestTypes::NoCtors,
std::string>;
const int x = 100;
int y = 42;
int z = 43;
V v(std::in_place_index<0>, -1);
// default emplace a value
v.emplace<1>();
assert(std::get<1>(v) == 0);
// emplace a reference
v.emplace<2>(x);
assert(&std::get<2>(v) == &x);
// emplace an rvalue reference
v.emplace<3>(std::move(y));
assert(&std::get<3>(v) == &y);
// re-emplace a new reference over the active member
v.emplace<3>(std::move(z));
assert(&std::get<3>(v) == &z);
// emplace with multiple args
v.emplace<5>(3, 'a');
assert(std::get<5>(v) == "aaa");
}
#endif
}
int main() {
test_basic();
test_emplace_sfinae();
}

View File

@@ -0,0 +1,85 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <size_t I, class U, class ...Args>
// void emplace(initializer_list<U> il,Args&&... args);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "archetypes.hpp"
#include "test_convertible.hpp"
#include "test_macros.h"
struct InitList {
std::size_t size;
constexpr InitList(std::initializer_list<int> il) : size(il.size()) {}
};
struct InitListArg {
std::size_t size;
int value;
constexpr InitListArg(std::initializer_list<int> il, int v)
: size(il.size()), value(v) {}
};
template <class Var, size_t I, class... Args>
constexpr auto test_emplace_exists_imp(int) -> decltype(
std::declval<Var>().template emplace<I>(std::declval<Args>()...), true) {
return true;
}
template <class, size_t, class...>
constexpr auto test_emplace_exists_imp(long) -> bool {
return false;
}
template <class Var, size_t I, class... Args> constexpr bool emplace_exists() {
return test_emplace_exists_imp<Var, I, Args...>(0);
}
void test_emplace_sfinae() {
using V =
std::variant<int, TestTypes::NoCtors, InitList, InitListArg, long, long>;
using IL = std::initializer_list<int>;
static_assert(!emplace_exists<V, 1, IL>(), "no such constructor");
static_assert(emplace_exists<V, 2, IL>(), "");
static_assert(!emplace_exists<V, 2, int>(), "args don't match");
static_assert(!emplace_exists<V, 2, IL, int>(), "too many args");
static_assert(emplace_exists<V, 3, IL, int>(), "");
static_assert(!emplace_exists<V, 3, int>(), "args don't match");
static_assert(!emplace_exists<V, 3, IL>(), "too few args");
static_assert(!emplace_exists<V, 3, IL, int, int>(), "too many args");
}
void test_basic() {
using V = std::variant<int, InitList, InitListArg, TestTypes::NoCtors>;
V v;
v.emplace<1>({1, 2, 3});
assert(std::get<1>(v).size == 3);
v.emplace<2>({1, 2, 3, 4}, 42);
assert(std::get<2>(v).size == 4);
assert(std::get<2>(v).value == 42);
v.emplace<1>({1});
assert(std::get<1>(v).size == 1);
}
int main() {
test_basic();
test_emplace_sfinae();
}

View File

@@ -0,0 +1,138 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <class T, class ...Args> void emplace(Args&&... args);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "archetypes.hpp"
#include "test_convertible.hpp"
#include "test_macros.h"
#include "variant_test_helpers.hpp"
template <class Var, class T, class... Args>
constexpr auto test_emplace_exists_imp(int) -> decltype(
std::declval<Var>().template emplace<T>(std::declval<Args>()...), true) {
return true;
}
template <class, class, class...>
constexpr auto test_emplace_exists_imp(long) -> bool {
return false;
}
template <class... Args> constexpr bool emplace_exists() {
return test_emplace_exists_imp<Args...>(0);
}
void test_emplace_sfinae() {
{
using V = std::variant<int, void *, const void *, TestTypes::NoCtors>;
static_assert(emplace_exists<V, int>(), "");
static_assert(emplace_exists<V, int, int>(), "");
static_assert(!emplace_exists<V, int, decltype(nullptr)>(),
"cannot construct");
static_assert(emplace_exists<V, void *, decltype(nullptr)>(), "");
static_assert(!emplace_exists<V, void *, int>(), "cannot construct");
static_assert(emplace_exists<V, void *, int *>(), "");
static_assert(!emplace_exists<V, void *, const int *>(), "");
static_assert(emplace_exists<V, void const *, const int *>(), "");
static_assert(emplace_exists<V, void const *, int *>(), "");
static_assert(!emplace_exists<V, TestTypes::NoCtors>(), "cannot construct");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
using V = std::variant<int, int &, int const &, int &&, long, long,
TestTypes::NoCtors>;
static_assert(emplace_exists<V, int>(), "");
static_assert(emplace_exists<V, int, int>(), "");
static_assert(emplace_exists<V, int, long long>(), "");
static_assert(!emplace_exists<V, int, int, int>(), "too many args");
static_assert(emplace_exists<V, int &, int &>(), "");
static_assert(!emplace_exists<V, int &>(), "cannot default construct ref");
static_assert(!emplace_exists<V, int &, int const &>(), "cannot bind ref");
static_assert(!emplace_exists<V, int &, int &&>(), "cannot bind ref");
static_assert(emplace_exists<V, int const &, int &>(), "");
static_assert(emplace_exists<V, int const &, const int &>(), "");
static_assert(emplace_exists<V, int const &, int &&>(), "");
static_assert(!emplace_exists<V, int const &, void *>(),
"not constructible from void*");
static_assert(emplace_exists<V, int &&, int>(), "");
static_assert(!emplace_exists<V, int &&, int &>(), "cannot bind ref");
static_assert(!emplace_exists<V, int &&, int const &>(), "cannot bind ref");
static_assert(!emplace_exists<V, int &&, int const &&>(), "cannot bind ref");
static_assert(!emplace_exists<V, long, long>(), "ambiguous");
static_assert(!emplace_exists<V, TestTypes::NoCtors>(),
"cannot construct void");
#endif
}
void test_basic() {
{
using V = std::variant<int>;
V v(42);
v.emplace<int>();
assert(std::get<0>(v) == 0);
v.emplace<int>(42);
assert(std::get<0>(v) == 42);
}
{
using V =
std::variant<int, long, const void *, TestTypes::NoCtors, std::string>;
const int x = 100;
V v(std::in_place_type<int>, -1);
// default emplace a value
v.emplace<long>();
assert(std::get<1>(v) == 0);
v.emplace<const void *>(&x);
assert(std::get<2>(v) == &x);
// emplace with multiple args
v.emplace<std::string>(3, 'a');
assert(std::get<4>(v) == "aaa");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
using V = std::variant<int, long, int const &, int &&, TestTypes::NoCtors,
std::string>;
const int x = 100;
int y = 42;
int z = 43;
V v(std::in_place_index<0>, -1);
// default emplace a value
v.emplace<long>();
assert(std::get<long>(v) == 0);
// emplace a reference
v.emplace<int const &>(x);
assert(&std::get<int const &>(v) == &x);
// emplace an rvalue reference
v.emplace<int &&>(std::move(y));
assert(&std::get<int &&>(v) == &y);
// re-emplace a new reference over the active member
v.emplace<int &&>(std::move(z));
assert(&std::get<int &&>(v) == &z);
// emplace with multiple args
v.emplace<std::string>(3, 'a');
assert(std::get<std::string>(v) == "aaa");
}
#endif
}
int main() {
test_basic();
test_emplace_sfinae();
}

View File

@@ -0,0 +1,85 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// template <class T, class U, class ...Args>
// void emplace(initializer_list<U> il,Args&&... args);
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "archetypes.hpp"
#include "test_convertible.hpp"
#include "test_macros.h"
struct InitList {
std::size_t size;
constexpr InitList(std::initializer_list<int> il) : size(il.size()) {}
};
struct InitListArg {
std::size_t size;
int value;
constexpr InitListArg(std::initializer_list<int> il, int v)
: size(il.size()), value(v) {}
};
template <class Var, class T, class... Args>
constexpr auto test_emplace_exists_imp(int) -> decltype(
std::declval<Var>().template emplace<T>(std::declval<Args>()...), true) {
return true;
}
template <class, class, class...>
constexpr auto test_emplace_exists_imp(long) -> bool {
return false;
}
template <class... Args> constexpr bool emplace_exists() {
return test_emplace_exists_imp<Args...>(0);
}
void test_emplace_sfinae() {
using V =
std::variant<int, TestTypes::NoCtors, InitList, InitListArg, long, long>;
using IL = std::initializer_list<int>;
static_assert(emplace_exists<V, InitList, IL>(), "");
static_assert(!emplace_exists<V, InitList, int>(), "args don't match");
static_assert(!emplace_exists<V, InitList, IL, int>(), "too many args");
static_assert(emplace_exists<V, InitListArg, IL, int>(), "");
static_assert(!emplace_exists<V, InitListArg, int>(), "args don't match");
static_assert(!emplace_exists<V, InitListArg, IL>(), "too few args");
static_assert(!emplace_exists<V, InitListArg, IL, int, int>(),
"too many args");
}
void test_basic() {
using V = std::variant<int, InitList, InitListArg, TestTypes::NoCtors>;
V v;
v.emplace<InitList>({1, 2, 3});
assert(std::get<InitList>(v).size == 3);
v.emplace<InitListArg>({1, 2, 3, 4}, 42);
assert(std::get<InitListArg>(v).size == 4);
assert(std::get<InitListArg>(v).value == 42);
v.emplace<InitList>({1});
assert(std::get<InitList>(v).size == 1);
}
int main() {
test_basic();
test_emplace_sfinae();
}

View File

@@ -0,0 +1,55 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// constexpr size_t index() const noexcept;
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "archetypes.hpp"
#include "test_macros.h"
#include "variant_test_helpers.hpp"
int main() {
{
using V = std::variant<int, ConstexprTestTypes::NoCtors>;
constexpr V v;
static_assert(v.index() == 0, "");
}
{
using V = std::variant<int, long>;
constexpr V v(std::in_place_index<1>);
static_assert(v.index() == 1, "");
}
{
using V = std::variant<int, std::string>;
V v("abc");
assert(v.index() == 1);
v = 42;
assert(v.index() == 0);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using V = std::variant<int, MakeEmptyT>;
V v;
assert(v.index() == 0);
makeEmpty(v);
assert(v.index() == std::variant_npos);
}
#endif
}

View File

@@ -0,0 +1,48 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// constexpr bool valueless_by_exception() const noexcept;
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "archetypes.hpp"
#include "test_macros.h"
#include "variant_test_helpers.hpp"
int main() {
{
using V = std::variant<int, ConstexprTestTypes::NoCtors>;
constexpr V v;
static_assert(!v.valueless_by_exception(), "");
}
{
using V = std::variant<int, long, std::string>;
const V v("abc");
assert(!v.valueless_by_exception());
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using V = std::variant<int, MakeEmptyT>;
V v;
assert(!v.valueless_by_exception());
makeEmpty(v);
assert(v.valueless_by_exception());
}
#endif
}

View File

@@ -0,0 +1,591 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
// void swap(variant& rhs) noexcept(see below)
#include <cassert>
#include <string>
#include <type_traits>
#include <variant>
#include "test_convertible.hpp"
#include "test_macros.h"
#include "variant_test_helpers.hpp"
struct NotSwappable {};
void swap(NotSwappable &, NotSwappable &) = delete;
struct NotCopyable {
NotCopyable() = default;
NotCopyable(NotCopyable const &) = delete;
NotCopyable &operator=(NotCopyable const &) = delete;
};
struct NotCopyableWithSwap {
NotCopyableWithSwap() = default;
NotCopyableWithSwap(NotCopyableWithSwap const &) = delete;
NotCopyableWithSwap &operator=(NotCopyableWithSwap const &) = delete;
};
void swap(NotCopyableWithSwap &, NotCopyableWithSwap) {}
struct NotMoveAssignable {
NotMoveAssignable() = default;
NotMoveAssignable(NotMoveAssignable &&) = default;
NotMoveAssignable &operator=(NotMoveAssignable &&) = delete;
};
struct NotMoveAssignableWithSwap {
NotMoveAssignableWithSwap() = default;
NotMoveAssignableWithSwap(NotMoveAssignableWithSwap &&) = default;
NotMoveAssignableWithSwap &operator=(NotMoveAssignableWithSwap &&) = delete;
};
void swap(NotMoveAssignableWithSwap &, NotMoveAssignableWithSwap &) noexcept {}
template <bool Throws> void do_throw() {}
template <> void do_throw<true>() {
#ifndef TEST_HAS_NO_EXCEPTIONS
throw 42;
#else
std::abort();
#endif
}
template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
bool NT_Swap, bool EnableSwap = true>
struct NothrowTypeImp {
static int move_called;
static int move_assign_called;
static int swap_called;
static void reset() { move_called = move_assign_called = swap_called = 0; }
NothrowTypeImp() = default;
explicit NothrowTypeImp(int v) : value(v) {}
NothrowTypeImp(NothrowTypeImp const &o) noexcept(NT_Copy) : value(o.value) {
assert(false);
} // never called by test
NothrowTypeImp(NothrowTypeImp &&o) noexcept(NT_Move) : value(o.value) {
++move_called;
do_throw<!NT_Move>();
o.value = -1;
}
NothrowTypeImp &operator=(NothrowTypeImp const &) noexcept(NT_CopyAssign) {
assert(false);
return *this;
} // never called by the tests
NothrowTypeImp &operator=(NothrowTypeImp &&o) noexcept(NT_MoveAssign) {
++move_assign_called;
do_throw<!NT_MoveAssign>();
value = o.value;
o.value = -1;
return *this;
}
int value;
};
template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
bool NT_Swap, bool EnableSwap>
int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
EnableSwap>::move_called = 0;
template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
bool NT_Swap, bool EnableSwap>
int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
EnableSwap>::move_assign_called = 0;
template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
bool NT_Swap, bool EnableSwap>
int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
EnableSwap>::swap_called = 0;
template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
bool NT_Swap>
void swap(NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign,
NT_Swap, true> &lhs,
NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign,
NT_Swap, true> &rhs) noexcept(NT_Swap) {
lhs.swap_called++;
do_throw<!NT_Swap>();
int tmp = lhs.value;
lhs.value = rhs.value;
rhs.value = tmp;
}
// throwing copy, nothrow move ctor/assign, no swap provided
using NothrowMoveable = NothrowTypeImp<false, true, false, true, false, false>;
// throwing copy and move assign, nothrow move ctor, no swap provided
using NothrowMoveCtor = NothrowTypeImp<false, true, false, false, false, false>;
// nothrow move ctor, throwing move assignment, swap provided
using NothrowMoveCtorWithThrowingSwap =
NothrowTypeImp<false, true, false, false, false, true>;
// throwing move ctor, nothrow move assignment, no swap provided
using ThrowingMoveCtor =
NothrowTypeImp<false, false, false, true, false, false>;
// throwing special members, nothrowing swap
using ThrowingTypeWithNothrowSwap =
NothrowTypeImp<false, false, false, false, true, true>;
using NothrowTypeWithThrowingSwap =
NothrowTypeImp<true, true, true, true, false, true>;
// throwing move assign with nothrow move and nothrow swap
using ThrowingMoveAssignNothrowMoveCtorWithSwap =
NothrowTypeImp<false, true, false, false, true, true>;
// throwing move assign with nothrow move but no swap.
using ThrowingMoveAssignNothrowMoveCtor =
NothrowTypeImp<false, true, false, false, false, false>;
struct NonThrowingNonNoexceptType {
static int move_called;
static void reset() { move_called = 0; }
NonThrowingNonNoexceptType() = default;
NonThrowingNonNoexceptType(int v) : value(v) {}
NonThrowingNonNoexceptType(NonThrowingNonNoexceptType &&o) noexcept(false)
: value(o.value) {
++move_called;
o.value = -1;
}
NonThrowingNonNoexceptType &
operator=(NonThrowingNonNoexceptType &&) noexcept(false) {
assert(false); // never called by the tests.
return *this;
}
int value;
};
int NonThrowingNonNoexceptType::move_called = 0;
struct ThrowsOnSecondMove {
int value;
int move_count;
ThrowsOnSecondMove(int v) : value(v), move_count(0) {}
ThrowsOnSecondMove(ThrowsOnSecondMove &&o) noexcept(false)
: value(o.value), move_count(o.move_count + 1) {
if (move_count == 2)
do_throw<true>();
o.value = -1;
}
ThrowsOnSecondMove &operator=(ThrowsOnSecondMove &&) {
assert(false); // not called by test
return *this;
}
};
void test_swap_valueless_by_exception() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using V = std::variant<int, MakeEmptyT>;
{ // both empty
V v1;
makeEmpty(v1);
V v2;
makeEmpty(v2);
assert(MakeEmptyT::alive == 0);
{ // member swap
v1.swap(v2);
assert(v1.valueless_by_exception());
assert(v2.valueless_by_exception());
assert(MakeEmptyT::alive == 0);
}
{ // non-member swap
swap(v1, v2);
assert(v1.valueless_by_exception());
assert(v2.valueless_by_exception());
assert(MakeEmptyT::alive == 0);
}
}
{ // only one empty
V v1(42);
V v2;
makeEmpty(v2);
{ // member swap
v1.swap(v2);
assert(v1.valueless_by_exception());
assert(std::get<0>(v2) == 42);
// swap again
v2.swap(v1);
assert(v2.valueless_by_exception());
assert(std::get<0>(v1) == 42);
}
{ // non-member swap
swap(v1, v2);
assert(v1.valueless_by_exception());
assert(std::get<0>(v2) == 42);
// swap again
swap(v1, v2);
assert(v2.valueless_by_exception());
assert(std::get<0>(v1) == 42);
}
}
#endif
}
void test_swap_same_alternative() {
{
using T = ThrowingTypeWithNothrowSwap;
using V = std::variant<T, int>;
T::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>, 100);
v1.swap(v2);
assert(T::swap_called == 1);
assert(std::get<0>(v1).value == 100);
assert(std::get<0>(v2).value == 42);
swap(v1, v2);
assert(T::swap_called == 2);
assert(std::get<0>(v1).value == 42);
assert(std::get<0>(v2).value == 100);
}
{
using T = NothrowMoveable;
using V = std::variant<T, int>;
T::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>, 100);
v1.swap(v2);
assert(T::swap_called == 0);
assert(T::move_called == 1);
assert(T::move_assign_called == 2);
assert(std::get<0>(v1).value == 100);
assert(std::get<0>(v2).value == 42);
T::reset();
swap(v1, v2);
assert(T::swap_called == 0);
assert(T::move_called == 1);
assert(T::move_assign_called == 2);
assert(std::get<0>(v1).value == 42);
assert(std::get<0>(v2).value == 100);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using T = NothrowTypeWithThrowingSwap;
using V = std::variant<T, int>;
T::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>, 100);
try {
v1.swap(v2);
assert(false);
} catch (int) {
}
assert(T::swap_called == 1);
assert(T::move_called == 0);
assert(T::move_assign_called == 0);
assert(std::get<0>(v1).value == 42);
assert(std::get<0>(v2).value == 100);
}
{
using T = ThrowingMoveCtor;
using V = std::variant<T, int>;
T::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>, 100);
try {
v1.swap(v2);
assert(false);
} catch (int) {
}
assert(T::move_called == 1); // call threw
assert(T::move_assign_called == 0);
assert(std::get<0>(v1).value ==
42); // throw happened before v1 was moved from
assert(std::get<0>(v2).value == 100);
}
{
using T = ThrowingMoveAssignNothrowMoveCtor;
using V = std::variant<T, int>;
T::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>, 100);
try {
v1.swap(v2);
assert(false);
} catch (int) {
}
assert(T::move_called == 1);
assert(T::move_assign_called == 1); // call threw and didn't complete
assert(std::get<0>(v1).value == -1); // v1 was moved from
assert(std::get<0>(v2).value == 100);
}
#endif
}
void test_swap_different_alternatives() {
{
using T = NothrowMoveCtorWithThrowingSwap;
using V = std::variant<T, int>;
T::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<1>, 100);
v1.swap(v2);
assert(T::swap_called == 0);
// The libc++ implementation double copies the argument, and not
// the variant swap is called on.
LIBCPP_ASSERT(T::move_called == 1);
assert(T::move_called <= 2);
assert(T::move_assign_called == 0);
assert(std::get<1>(v1) == 100);
assert(std::get<0>(v2).value == 42);
T::reset();
swap(v1, v2);
assert(T::swap_called == 0);
LIBCPP_ASSERT(T::move_called == 2);
assert(T::move_called <= 2);
assert(T::move_assign_called == 0);
assert(std::get<0>(v1).value == 42);
assert(std::get<1>(v2) == 100);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using T1 = ThrowingTypeWithNothrowSwap;
using T2 = NonThrowingNonNoexceptType;
using V = std::variant<T1, T2>;
T1::reset();
T2::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<1>, 100);
try {
v1.swap(v2);
assert(false);
} catch (int) {
}
assert(T1::swap_called == 0);
assert(T1::move_called == 1); // throws
assert(T1::move_assign_called == 0);
// FIXME: libc++ shouldn't move from T2 here.
LIBCPP_ASSERT(T2::move_called == 1);
assert(T2::move_called <= 1);
assert(std::get<0>(v1).value == 42);
if (T2::move_called != 0)
assert(v2.valueless_by_exception());
else
assert(std::get<1>(v2).value == 100);
}
{
using T1 = NonThrowingNonNoexceptType;
using T2 = ThrowingTypeWithNothrowSwap;
using V = std::variant<T1, T2>;
T1::reset();
T2::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<1>, 100);
try {
v1.swap(v2);
assert(false);
} catch (int) {
}
LIBCPP_ASSERT(T1::move_called == 0);
assert(T1::move_called <= 1);
assert(T2::swap_called == 0);
assert(T2::move_called == 1); // throws
assert(T2::move_assign_called == 0);
if (T1::move_called != 0)
assert(v1.valueless_by_exception());
else
assert(std::get<0>(v1).value == 42);
assert(std::get<1>(v2).value == 100);
}
// FIXME: The tests below are just very libc++ specific
#ifdef _LIBCPP_VERSION
{
using T1 = ThrowsOnSecondMove;
using T2 = NonThrowingNonNoexceptType;
using V = std::variant<T1, T2>;
T2::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<1>, 100);
v1.swap(v2);
assert(T2::move_called == 2);
assert(std::get<1>(v1).value == 100);
assert(std::get<0>(v2).value == 42);
assert(std::get<0>(v2).move_count == 1);
}
{
using T1 = NonThrowingNonNoexceptType;
using T2 = ThrowsOnSecondMove;
using V = std::variant<T1, T2>;
T1::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<1>, 100);
try {
v1.swap(v2);
assert(false);
} catch (int) {
}
assert(T1::move_called == 1);
assert(v1.valueless_by_exception());
assert(std::get<0>(v2).value == 42);
}
#endif
// testing libc++ extension. If either variant stores a nothrow move
// constructible type v1.swap(v2) provides the strong exception safety
// guarantee.
#ifdef _LIBCPP_VERSION
{
using T1 = ThrowingTypeWithNothrowSwap;
using T2 = NothrowMoveable;
using V = std::variant<T1, T2>;
T1::reset();
T2::reset();
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<1>, 100);
try {
v1.swap(v2);
assert(false);
} catch (int) {
}
assert(T1::swap_called == 0);
assert(T1::move_called == 1);
assert(T1::move_assign_called == 0);
assert(T2::swap_called == 0);
assert(T2::move_called == 2);
assert(T2::move_assign_called == 0);
assert(std::get<0>(v1).value == 42);
assert(std::get<1>(v2).value == 100);
// swap again, but call v2's swap.
T1::reset();
T2::reset();
try {
v2.swap(v1);
assert(false);
} catch (int) {
}
assert(T1::swap_called == 0);
assert(T1::move_called == 1);
assert(T1::move_assign_called == 0);
assert(T2::swap_called == 0);
assert(T2::move_called == 2);
assert(T2::move_assign_called == 0);
assert(std::get<0>(v1).value == 42);
assert(std::get<1>(v2).value == 100);
}
#endif // _LIBCPP_VERSION
#endif
}
template <class Var>
constexpr auto has_swap_member_imp(int)
-> decltype(std::declval<Var &>().swap(std::declval<Var &>()), true) {
return true;
}
template <class Var> constexpr auto has_swap_member_imp(long) -> bool {
return false;
}
template <class Var> constexpr bool has_swap_member() {
return has_swap_member_imp<Var>(0);
}
void test_swap_sfinae() {
{
// This variant type does not provide either a member or non-member swap
// but is still swappable via the generic swap algorithm, since the
// variant is move constructible and move assignable.
using V = std::variant<int, NotSwappable>;
LIBCPP_STATIC_ASSERT(!has_swap_member<V>());
static_assert(std::is_swappable_v<V>, "");
}
{
using V = std::variant<int, NotCopyable>;
LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
static_assert(!std::is_swappable_v<V>, "");
}
{
using V = std::variant<int, NotCopyableWithSwap>;
LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
static_assert(!std::is_swappable_v<V>, "");
}
{
using V = std::variant<int, NotMoveAssignable>;
LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
static_assert(!std::is_swappable_v<V>, "");
}
}
void test_swap_noexcept() {
{
using V = std::variant<int, NothrowMoveable>;
static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
static_assert(std::is_nothrow_swappable_v<V>, "");
// instantiate swap
V v1, v2;
v1.swap(v2);
swap(v1, v2);
}
{
using V = std::variant<int, NothrowMoveCtor>;
static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
static_assert(!std::is_nothrow_swappable_v<V>, "");
// instantiate swap
V v1, v2;
v1.swap(v2);
swap(v1, v2);
}
{
using V = std::variant<int, ThrowingTypeWithNothrowSwap>;
static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
static_assert(!std::is_nothrow_swappable_v<V>, "");
// instantiate swap
V v1, v2;
v1.swap(v2);
swap(v1, v2);
}
{
using V = std::variant<int, ThrowingMoveAssignNothrowMoveCtor>;
static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
static_assert(!std::is_nothrow_swappable_v<V>, "");
// instantiate swap
V v1, v2;
v1.swap(v2);
swap(v1, v2);
}
{
using V = std::variant<int, ThrowingMoveAssignNothrowMoveCtorWithSwap>;
static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
static_assert(std::is_nothrow_swappable_v<V>, "");
// instantiate swap
V v1, v2;
v1.swap(v2);
swap(v1, v2);
}
{
using V = std::variant<int, NotMoveAssignableWithSwap>;
static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
static_assert(std::is_nothrow_swappable_v<V>, "");
// instantiate swap
V v1, v2;
v1.swap(v2);
swap(v1, v2);
}
{
// This variant type does not provide either a member or non-member swap
// but is still swappable via the generic swap algorithm, since the
// variant is move constructible and move assignable.
using V = std::variant<int, NotSwappable>;
LIBCPP_STATIC_ASSERT(!has_swap_member<V>());
static_assert(std::is_swappable_v<V>, "");
static_assert(std::is_nothrow_swappable_v<V>, "");
V v1, v2;
swap(v1, v2);
}
}
// This is why variant should SFINAE member swap. :-)
LIBCPP_ONLY(template class std::variant<int, NotSwappable>;)
int main() {
test_swap_valueless_by_exception();
test_swap_same_alternative();
test_swap_different_alternatives();
test_swap_sfinae();
test_swap_noexcept();
}

View File

@@ -0,0 +1,33 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
#include <variant>
#include <type_traits>
#include <string>
#include <cassert>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
#include "test_convertible.hpp"
int main()
{
// expected-error@variant:* 3 {{static_assert failed}}
std::variant<int, int[]> v; // expected-note {{requested here}}
std::variant<int, int[42]> v2; // expected-note {{requested here}}
std::variant<int, int[][42]> v3; // expected-note {{requested here}}
}

View File

@@ -0,0 +1,26 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
#include <variant>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
int main()
{
// expected-error@variant:* 1 {{static_assert failed}}
std::variant<> v; // expected-note {{requested here}}
}

View File

@@ -0,0 +1,28 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
#include <variant>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
int main()
{
// expected-error@variant:* 3 {{static_assert failed}}
std::variant<int, int&> v; // expected-note {{requested here}}
std::variant<int, int const&> v2; // expected-note {{requested here}}
std::variant<int, int&&> v3; // expected-note {{requested here}}
}

View File

@@ -0,0 +1,33 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class ...Types> class variant;
#include <variant>
#include <type_traits>
#include <string>
#include <cassert>
#include "test_macros.h"
#include "variant_test_helpers.hpp"
#include "test_convertible.hpp"
int main()
{
// expected-error@variant:* 3 {{static_assert failed}}
std::variant<int, void> v; // expected-note {{requested here}}
std::variant<int, const void> v2; // expected-note {{requested here}}
std::variant<const volatile void, int> v3; // expected-note {{requested here}}
}

View File

@@ -0,0 +1,291 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
// <variant>
// template <class Visitor, class... Variants>
// constexpr see below visit(Visitor&& vis, Variants&&... vars);
#include <cassert>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include "test_macros.h"
#include "type_id.h"
#include "variant_test_helpers.hpp"
enum CallType : unsigned {
CT_None,
CT_NonConst = 1,
CT_Const = 2,
CT_LValue = 4,
CT_RValue = 8
};
inline constexpr CallType operator|(CallType LHS, CallType RHS) {
return static_cast<CallType>(static_cast<unsigned>(LHS) |
static_cast<unsigned>(RHS));
}
struct ForwardingCallObject {
template <class... Args> bool operator()(Args &&...) & {
set_call<Args &&...>(CT_NonConst | CT_LValue);
return true;
}
template <class... Args> bool operator()(Args &&...) const & {
set_call<Args &&...>(CT_Const | CT_LValue);
return true;
}
// Don't allow the call operator to be invoked as an rvalue.
template <class... Args> bool operator()(Args &&...) && {
set_call<Args &&...>(CT_NonConst | CT_RValue);
return true;
}
template <class... Args> bool operator()(Args &&...) const && {
set_call<Args &&...>(CT_Const | CT_RValue);
return true;
}
template <class... Args> static void set_call(CallType type) {
assert(last_call_type == CT_None);
assert(last_call_args == nullptr);
last_call_type = type;
last_call_args = std::addressof(makeArgumentID<Args...>());
}
template <class... Args> static bool check_call(CallType type) {
bool result = last_call_type == type && last_call_args &&
*last_call_args == makeArgumentID<Args...>();
last_call_type = CT_None;
last_call_args = nullptr;
return result;
}
static CallType last_call_type;
static TypeID const *last_call_args;
};
CallType ForwardingCallObject::last_call_type = CT_None;
TypeID const *ForwardingCallObject::last_call_args = nullptr;
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
Fn const &cobj = obj;
{ // test call operator forwarding - single variant, single arg
using V = std::variant<int>;
V v(42);
std::visit(obj, v);
assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
std::visit(cobj, v);
assert(Fn::check_call<int &>(CT_Const | CT_LValue));
std::visit(std::move(obj), v);
assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
std::visit(std::move(cobj), v);
assert(Fn::check_call<int &>(CT_Const | CT_RValue));
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
V v(42l);
std::visit(obj, v);
assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
std::visit(cobj, v);
assert(Fn::check_call<long &>(CT_Const | CT_LValue));
std::visit(std::move(obj), v);
assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
std::visit(std::move(cobj), v);
assert(Fn::check_call<long &>(CT_Const | CT_RValue));
}
{ // test call operator forwarding - multi variant, multi arg
using V = std::variant<int, long, double>;
using V2 = std::variant<int *, std::string>;
V v(42l);
V2 v2("hello");
std::visit(obj, v, v2);
assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
std::visit(cobj, v, v2);
assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
std::visit(std::move(obj), v, v2);
assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
std::visit(std::move(cobj), v, v2);
assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
}
}
void test_argument_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
const auto Val = CT_LValue | CT_NonConst;
{ // single argument - value type
using V = std::variant<int>;
V v(42);
V const &cv = v;
std::visit(obj, v);
assert(Fn::check_call<int &>(Val));
std::visit(obj, cv);
assert(Fn::check_call<int const &>(Val));
std::visit(obj, std::move(v));
assert(Fn::check_call<int &&>(Val));
std::visit(obj, std::move(cv));
assert(Fn::check_call<const int &&>(Val));
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{ // single argument - lvalue reference
using V = std::variant<int &>;
int x = 42;
V v(x);
V const &cv = v;
std::visit(obj, v);
assert(Fn::check_call<int &>(Val));
std::visit(obj, cv);
assert(Fn::check_call<int &>(Val));
std::visit(obj, std::move(v));
assert(Fn::check_call<int &>(Val));
std::visit(obj, std::move(cv));
assert(Fn::check_call<int &>(Val));
}
{ // single argument - rvalue reference
using V = std::variant<int &&>;
int x = 42;
V v(std::move(x));
V const &cv = v;
std::visit(obj, v);
assert(Fn::check_call<int &>(Val));
std::visit(obj, cv);
assert(Fn::check_call<int &>(Val));
std::visit(obj, std::move(v));
assert(Fn::check_call<int &&>(Val));
std::visit(obj, std::move(cv));
assert(Fn::check_call<int &&>(Val));
}
{ // multi argument - multi variant
using S = std::string const &;
using V = std::variant<int, S, long &&>;
std::string const str = "hello";
long l = 43;
V v1(42);
V const &cv1 = v1;
V v2(str);
V const &cv2 = v2;
V v3(std::move(l));
V const &cv3 = v3;
std::visit(obj, v1, v2, v3);
assert((Fn::check_call<int &, S, long &>(Val)));
std::visit(obj, cv1, cv2, std::move(v3));
assert((Fn::check_call<const int &, S, long &&>(Val)));
}
#endif
}
struct ReturnFirst {
template <class... Args> constexpr int operator()(int f, Args &&...) const {
return f;
}
};
struct ReturnArity {
template <class... Args> constexpr int operator()(Args &&...) const {
return sizeof...(Args);
}
};
void test_constexpr() {
constexpr ReturnFirst obj{};
constexpr ReturnArity aobj{};
{
using V = std::variant<int>;
constexpr V v(42);
static_assert(std::visit(obj, v) == 42, "");
}
{
using V = std::variant<short, long, char>;
constexpr V v(42l);
static_assert(std::visit(obj, v) == 42, "");
}
{
using V1 = std::variant<int>;
using V2 = std::variant<int, char *, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
constexpr V3 v3;
static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
}
{
using V1 = std::variant<int>;
using V2 = std::variant<int, char *, long long>;
using V3 = std::variant<void *, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
constexpr V3 v3;
static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
}
}
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
auto test = [&](auto &&... args) {
try {
std::visit(obj, args...);
} catch (std::bad_variant_access const &) {
return true;
} catch (...) {
}
return false;
};
{
using V = std::variant<int, MakeEmptyT>;
V v;
makeEmpty(v);
assert(test(v));
}
{
using V = std::variant<int, MakeEmptyT>;
using V2 = std::variant<long, std::string, void *>;
V v;
makeEmpty(v);
V2 v2("hello");
assert(test(v, v2));
}
{
using V = std::variant<int, MakeEmptyT>;
using V2 = std::variant<long, std::string, void *>;
V v;
makeEmpty(v);
V2 v2("hello");
assert(test(v2, v));
}
{
using V = std::variant<int, MakeEmptyT>;
using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
V v;
makeEmpty(v);
V2 v2;
makeEmpty(v2);
assert(test(v, v2));
}
#endif
}
int main() {
test_call_operator_forwarding();
test_argument_forwarding();
test_constexpr();
test_exceptions();
}

View File

@@ -42,7 +42,6 @@ struct AllCtors : DEFINE_BASE(AllCtors) {
struct NoCtors : DEFINE_BASE(NoCtors) { struct NoCtors : DEFINE_BASE(NoCtors) {
using Base = DEFINE_BASE(NoCtors); using Base = DEFINE_BASE(NoCtors);
using Base::Base;
DEFINE_EXPLICIT NoCtors() = delete; DEFINE_EXPLICIT NoCtors() = delete;
DEFINE_EXPLICIT NoCtors(NoCtors const&) = delete; DEFINE_EXPLICIT NoCtors(NoCtors const&) = delete;
NoCtors& operator=(NoCtors const&) = delete; NoCtors& operator=(NoCtors const&) = delete;

View File

@@ -0,0 +1,81 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
#ifndef SUPPORT_VARIANT_TEST_HELPERS_HPP
#define SUPPORT_VARIANT_TEST_HELPERS_HPP
#include <type_traits>
#include <utility>
#include <cassert>
#include "test_macros.h"
#if TEST_STD_VER <= 14
#error This file requires C++17
#endif
// FIXME: Currently the variant<T&> tests are disabled using this macro.
#define TEST_VARIANT_HAS_NO_REFERENCES
#ifndef TEST_HAS_NO_EXCEPTIONS
struct CopyThrows {
CopyThrows() = default;
CopyThrows(CopyThrows const&) { throw 42; }
CopyThrows& operator=(CopyThrows const&) { throw 42; }
};
struct MoveThrows {
static int alive;
MoveThrows() { ++alive; }
MoveThrows(MoveThrows const&) {++alive;}
MoveThrows(MoveThrows&&) { throw 42; }
MoveThrows& operator=(MoveThrows const&) { return *this; }
MoveThrows& operator=(MoveThrows&&) { throw 42; }
~MoveThrows() { --alive; }
};
int MoveThrows::alive = 0;
struct MakeEmptyT {
static int alive;
MakeEmptyT() { ++alive; }
MakeEmptyT(MakeEmptyT const&) {
++alive;
// Don't throw from the copy constructor since variant's assignment
// operator performs a copy before committing to the assignment.
}
MakeEmptyT(MakeEmptyT &&) {
throw 42;
}
MakeEmptyT& operator=(MakeEmptyT const&) {
throw 42;
}
MakeEmptyT& operator=(MakeEmptyT&&) {
throw 42;
}
~MakeEmptyT() { --alive; }
};
static_assert(std::is_swappable_v<MakeEmptyT>, ""); // required for test
int MakeEmptyT::alive = 0;
template <class Variant>
void makeEmpty(Variant& v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = v2;
assert(false);
} catch (...) {
assert(v.valueless_by_exception());
}
}
#endif // TEST_HAS_NO_EXCEPTIONS
#endif // SUPPORT_VARIANT_TEST_HELPERS_HPP