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:
@@ -233,6 +233,7 @@ class Configuration(object):
|
||||
self.lit_config.fatal(
|
||||
'unsupported value for "cxx_stdlib_under_test": %s'
|
||||
% self.cxx_stdlib_under_test)
|
||||
self.config.available_features.add(self.cxx_stdlib_under_test)
|
||||
if self.cxx_stdlib_under_test == 'libstdc++':
|
||||
self.config.available_features.add('libstdc++')
|
||||
# Manually enable the experimental and filesystem tests for libstdc++
|
||||
|
||||
5
test/std/utilities/variant/lit.local.cfg
Normal file
5
test/std/utilities/variant/lit.local.cfg
Normal 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
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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() {}
|
||||
132
test/std/utilities/variant/variant.get/get_if_index.pass.cpp
Normal file
132
test/std/utilities/variant/variant.get/get_if_index.pass.cpp
Normal 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();
|
||||
}
|
||||
130
test/std/utilities/variant/variant.get/get_if_type.pass.cpp
Normal file
130
test/std/utilities/variant/variant.get/get_if_type.pass.cpp
Normal 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();
|
||||
}
|
||||
268
test/std/utilities/variant/variant.get/get_index.pass.cpp
Normal file
268
test/std/utilities/variant/variant.get/get_index.pass.cpp
Normal 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();
|
||||
}
|
||||
266
test/std/utilities/variant/variant.get/get_type.pass.cpp
Normal file
266
test/std/utilities/variant/variant.get/get_type.pass.cpp
Normal 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();
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
112
test/std/utilities/variant/variant.hash/hash.pass.cpp
Normal file
112
test/std/utilities/variant/variant.hash/hash.pass.cpp
Normal 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();
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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), "");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
227
test/std/utilities/variant/variant.relops/relops.pass.cpp
Normal file
227
test/std/utilities/variant/variant.relops/relops.pass.cpp
Normal 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();
|
||||
}
|
||||
@@ -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), "");
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
291
test/std/utilities/variant/variant.visit/visit.pass.cpp
Normal file
291
test/std/utilities/variant/variant.visit/visit.pass.cpp
Normal 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();
|
||||
}
|
||||
@@ -42,7 +42,6 @@ struct AllCtors : DEFINE_BASE(AllCtors) {
|
||||
|
||||
struct NoCtors : DEFINE_BASE(NoCtors) {
|
||||
using Base = DEFINE_BASE(NoCtors);
|
||||
using Base::Base;
|
||||
DEFINE_EXPLICIT NoCtors() = delete;
|
||||
DEFINE_EXPLICIT NoCtors(NoCtors const&) = delete;
|
||||
NoCtors& operator=(NoCtors const&) = delete;
|
||||
|
||||
81
test/support/variant_test_helpers.hpp
Normal file
81
test/support/variant_test_helpers.hpp
Normal 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
|
||||
Reference in New Issue
Block a user