diff options
author | Eric Fiselier <eric@efcs.ca> | 2016-10-12 07:46:20 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2016-10-12 07:46:20 +0000 |
commit | a9e659619f592c49b352af16253ec0b79c207956 (patch) | |
tree | afba7c02efb5a36d4fb797262d8b0db50da64c49 /libcxx/test/std/utilities/optional/optional.object/optional.object.assign | |
parent | 90d990e034f05f4d9e0354f54205fd3b471f6507 (diff) | |
download | bcm5719-llvm-a9e659619f592c49b352af16253ec0b79c207956.tar.gz bcm5719-llvm-a9e659619f592c49b352af16253ec0b79c207956.zip |
Implement N4606 optional
Summary:
Adapt implementation of Library Fundamentals TS optional into an implementation of N4606 optional.
- Update relational operators per http://wg21.link/P0307
- Update to requirements of http://wg21.link/P0032
- Extension: Implement trivial copy/move construction/assignment for `optional<T>` when `T` is trivially copyable.
Audit P/Rs for optional LWG issues:
- 2756 "C++ WP optional<T> should 'forward' T's implicit conversions" Implemented, which also resolves 2753 "Optional's constructors and assignments need constraints" (modulo my refusal to explicitly delete the move operations, which is a design error that I'm working on correcting in the 2756 P/R).
- 2736 "nullopt_t insufficiently constrained" Already conforming. I've added a test ensuring that `nullopt_t` is not copy-initializable from an empty braced-init-list, which I believe is the root intent of the issue, to avoid regression.
- 2740 "constexpr optional<T>::operator->" Already conforming.
- 2746 "Inconsistency between requirements for emplace between optional and variant" No P/R, but note that the author's '"suggested resolution" is already implemented.
- 2748 "swappable traits for optionals" Already conforming.
- 2753 "Optional's constructors and assignments need constraints" Implemented.
Most of the work for this patch was done by Casey Carter @ Microsoft. Thank you Casey!
Reviewers: mclow.lists, CaseyCarter, EricWF
Differential Revision: https://reviews.llvm.org/D22741
llvm-svn: 283980
Diffstat (limited to 'libcxx/test/std/utilities/optional/optional.object/optional.object.assign')
8 files changed, 1476 insertions, 0 deletions
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp new file mode 100644 index 00000000000..6abdd0db63c --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp @@ -0,0 +1,261 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// <optional> + +// template <class U> optional<T>& operator=(U&& v); + +#include <optional> +#include <type_traits> +#include <cassert> +#include <memory> + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; + +struct ThrowAssign { + static int dtor_called; + ThrowAssign() = default; + ThrowAssign(int) { TEST_THROW(42); } + ThrowAssign& operator=(int) { + TEST_THROW(42); + } + ~ThrowAssign() { ++dtor_called; } +}; +int ThrowAssign::dtor_called = 0; + +template <class T, class Arg = T, bool Expect = true> +void assert_assignable() { + static_assert(std::is_assignable<optional<T>&, Arg>::value == Expect, ""); + static_assert(!std::is_assignable<const optional<T>&, Arg>::value, ""); +} + +struct MismatchType { + explicit MismatchType(int) {} + explicit MismatchType(char*) {} + explicit MismatchType(int*) = delete; + MismatchType& operator=(int) { return *this; } + MismatchType& operator=(int*) { return *this; } + MismatchType& operator=(char*) = delete; +}; + +void test_sfinae() { + using I = TestTypes::TestType; + using E = ExplicitTestTypes::TestType; + assert_assignable<int>(); + assert_assignable<int, int&>(); + assert_assignable<int, int const&>(); + // Implicit test type + assert_assignable<I, I const&>(); + assert_assignable<I, I&&>(); + assert_assignable<I, int>(); + assert_assignable<I, void*, false>(); + // Explicit test type + assert_assignable<E, E const&>(); + assert_assignable<E, E &&>(); + assert_assignable<E, int>(); + assert_assignable<E, void*, false>(); + // Mismatch type + assert_assignable<MismatchType, int>(); + assert_assignable<MismatchType, int*, false>(); + assert_assignable<MismatchType, char*, false>(); +} + +void test_with_test_type() +{ + using T = TestTypes::TestType; + T::reset(); + { // to empty + optional<T> opt; + opt = 3; + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::assigned == 0); + assert(T::destroyed == 0); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(3)); + } + { // to existing + optional<T> opt(42); + T::reset_constructors(); + opt = 3; + assert(T::alive == 1); + assert(T::constructed == 0); + assert(T::assigned == 1); + assert(T::value_assigned == 1); + assert(T::destroyed == 0); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(3)); + } + { // test default argument + optional<T> opt; + T::reset_constructors(); + opt = {1, 2}; + assert(T::alive == 1); + assert(T::constructed == 2); + assert(T::value_constructed == 1); + assert(T::move_constructed == 1); + assert(T::assigned == 0); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(1, 2)); + } + { // test default argument + optional<T> opt(42); + T::reset_constructors(); + opt = {1, 2}; + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::assigned == 1); + assert(T::move_assigned == 1); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(1, 2)); + } + { // test default argument + optional<T> opt; + T::reset_constructors(); + opt = {1}; + assert(T::alive == 1); + assert(T::constructed == 2); + assert(T::value_constructed == 1); + assert(T::move_constructed == 1); + assert(T::assigned == 0); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(1)); + } + { // test default argument + optional<T> opt(42); + T::reset_constructors(); + opt = {}; + assert(static_cast<bool>(opt) == false); + assert(T::alive == 0); + assert(T::constructed == 0); + assert(T::assigned == 0); + assert(T::destroyed == 1); + } +} + +template <class T, class Value = int> +void test_with_type() { + { // to empty + optional<T> opt; + opt = Value(3); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(3)); + } + { // to existing + optional<T> opt(Value(42)); + opt = Value(3); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(3)); + } + { // test const + optional<T> opt(Value(42)); + const T t(Value(3)); + opt = t; + assert(static_cast<bool>(opt) == true); + assert(*opt == T(3)); + } + { // test default argument + optional<T> opt; + opt = {Value(1)}; + assert(static_cast<bool>(opt) == true); + assert(*opt == T(1)); + } + { // test default argument + optional<T> opt(Value(42)); + opt = {}; + assert(static_cast<bool>(opt) == false); + } +} + +template <class T> +void test_with_type_multi() { + test_with_type<T>(); + { // test default argument + optional<T> opt; + opt = {1, 2}; + assert(static_cast<bool>(opt) == true); + assert(*opt == T(1, 2)); + } + { // test default argument + optional<T> opt(42); + opt = {1, 2}; + assert(static_cast<bool>(opt) == true); + assert(*opt == T(1, 2)); + } +} + +void test_throws() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using T = ThrowAssign; + { + using T = ThrowAssign; + optional<T> opt; + try { + opt = 42; + assert(false); + } catch (int) {} + assert(static_cast<bool>(opt) == false); + } + assert(T::dtor_called == 0); + { + T::dtor_called = 0; + optional<T> opt(std::in_place); + try { + opt = 42; + assert(false); + } catch (int) {} + assert(static_cast<bool>(opt) == true); + assert(T::dtor_called == 0); + } + assert(T::dtor_called == 1); +#endif +} + +enum MyEnum { Zero, One, Two, Three, FortyTwo = 42 }; + +using Fn = void(*)(); + +int main() +{ + test_sfinae(); + // Test with instrumented type + test_with_test_type(); + // Test with various scalar types + test_with_type<int>(); + test_with_type<MyEnum, MyEnum>(); + test_with_type<int, MyEnum>(); + test_with_type<Fn, Fn>(); + // Test types with multi argument constructors + test_with_type_multi<ConstexprTestTypes::TestType>(); + test_with_type_multi<TrivialTestTypes::TestType>(); + // Test move only types + { + optional<std::unique_ptr<int>> opt; + opt = std::unique_ptr<int>(new int(3)); + assert(static_cast<bool>(opt) == true); + assert(**opt == 3); + } + { + optional<std::unique_ptr<int>> opt(std::unique_ptr<int>(new int(2))); + opt = std::unique_ptr<int>(new int(3)); + assert(static_cast<bool>(opt) == true); + assert(**opt == 3); + } + test_throws(); +} diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp new file mode 100644 index 00000000000..d471c053c90 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp @@ -0,0 +1,254 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// <optional> + +// From LWG2451: +// template<class U> +// optional<T>& operator=(const optional<U>& rhs); + +#include <optional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; + +struct X +{ + static bool throw_now; + + X() = default; + X(int) + { + if (throw_now) + TEST_THROW(6); + } +}; + +bool X::throw_now = false; + +struct Y1 +{ + Y1() = default; + Y1(const int&) {} + Y1& operator=(const Y1&) = delete; +}; + +struct Y2 +{ + Y2() = default; + Y2(const int&) = delete; + Y2& operator=(const int&) { return *this; } +}; + +template <class T> +struct AssignableFrom { + static int type_constructed; + static int type_assigned; +static int int_constructed; + static int int_assigned; + + static void reset() { + type_constructed = int_constructed = 0; + type_assigned = int_assigned = 0; + } + + AssignableFrom() = default; + + explicit AssignableFrom(T) { ++type_constructed; } + AssignableFrom& operator=(T) { ++type_assigned; return *this; } + + AssignableFrom(int) { ++int_constructed; } + AssignableFrom& operator=(int) { ++int_assigned; return *this; } +private: + AssignableFrom(AssignableFrom const&) = delete; + AssignableFrom& operator=(AssignableFrom const&) = delete; +}; + +template <class T> int AssignableFrom<T>::type_constructed = 0; +template <class T> int AssignableFrom<T>::type_assigned = 0; +template <class T> int AssignableFrom<T>::int_constructed = 0; +template <class T> int AssignableFrom<T>::int_assigned = 0; + + +void test_with_test_type() { + using T = TestTypes::TestType; + T::reset(); + { // non-empty to empty + T::reset_constructors(); + optional<T> opt; + const optional<int> other(42); + opt = other; + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::assigned == 0); + assert(T::destroyed == 0); + assert(static_cast<bool>(other) == true); + assert(*other == 42); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(42)); + } + assert(T::alive == 0); + { // non-empty to non-empty + optional<T> opt(101); + const optional<int> other(42); + T::reset_constructors(); + opt = other; + assert(T::alive == 1); + assert(T::constructed == 0); + assert(T::assigned == 1); + assert(T::value_assigned == 1); + assert(T::destroyed == 0); + assert(static_cast<bool>(other) == true); + assert(*other == 42); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(42)); + } + assert(T::alive == 0); + { // empty to non-empty + optional<T> opt(101); + const optional<int> other; + T::reset_constructors(); + opt = other; + assert(T::alive == 0); + assert(T::constructed == 0); + assert(T::assigned == 0); + assert(T::destroyed == 1); + assert(static_cast<bool>(other) == false); + assert(static_cast<bool>(opt) == false); + } + assert(T::alive == 0); + { // empty to empty + optional<T> opt; + const optional<int> other; + T::reset_constructors(); + opt = other; + assert(T::alive == 0); + assert(T::constructed == 0); + assert(T::assigned == 0); + assert(T::destroyed == 0); + assert(static_cast<bool>(other) == false); + assert(static_cast<bool>(opt) == false); + } + assert(T::alive == 0); +} + +void test_ambigious_assign() { + using OptInt = std::optional<int>; + { + using T = AssignableFrom<OptInt const&>; + const OptInt a(42); + T::reset(); + { + std::optional<T> t; + t = a; + assert(T::type_constructed == 1); + assert(T::type_assigned == 0); + assert(T::int_constructed == 0); + assert(T::int_assigned == 0); + } + T::reset(); + { + std::optional<T> t(42); + t = a; + assert(T::type_constructed == 0); + assert(T::type_assigned == 1); + assert(T::int_constructed == 1); + assert(T::int_assigned == 0); + } + T::reset(); + { + std::optional<T> t(42); + t = std::move(a); + assert(T::type_constructed == 0); + assert(T::type_assigned == 1); + assert(T::int_constructed == 1); + assert(T::int_assigned == 0); + } + } + { + using T = AssignableFrom<OptInt&>; + OptInt a(42); + T::reset(); + { + std::optional<T> t; + t = a; + assert(T::type_constructed == 1); + assert(T::type_assigned == 0); + assert(T::int_constructed == 0); + assert(T::int_assigned == 0); + } + { + using Opt = std::optional<T>; + static_assert(!std::is_assignable_v<Opt&, OptInt const&>, ""); + } + } +} + + +int main() +{ + test_with_test_type(); + test_ambigious_assign(); + { + optional<int> opt; + constexpr optional<short> opt2; + opt = opt2; + static_assert(static_cast<bool>(opt2) == false, ""); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + } + { + optional<int> opt; + constexpr optional<short> opt2(short{2}); + opt = opt2; + static_assert(static_cast<bool>(opt2) == true, ""); + static_assert(*opt2 == 2, ""); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + assert(*opt == *opt2); + } + { + optional<int> opt(3); + constexpr optional<short> opt2; + opt = opt2; + static_assert(static_cast<bool>(opt2) == false, ""); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + } + { + optional<int> opt(3); + constexpr optional<short> opt2(short{2}); + opt = opt2; + static_assert(static_cast<bool>(opt2) == true, ""); + static_assert(*opt2 == 2, ""); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + assert(*opt == *opt2); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + optional<X> opt; + optional<int> opt2(42); + assert(static_cast<bool>(opt2) == true); + try + { + X::throw_now = true; + opt = opt2; + assert(false); + } + catch (int i) + { + assert(i == 6); + assert(static_cast<bool>(opt) == false); + } + } +#endif +} diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp new file mode 100644 index 00000000000..98c90aa1d4f --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// <optional> + +// optional<T>& operator=(const optional<T>& rhs); + +#include <optional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; + +struct X +{ + static bool throw_now; + + X() = default; + X(const X&) + { + if (throw_now) + TEST_THROW(6); + } +}; + +bool X::throw_now = false; + +template <class Tp> +constexpr bool assign_empty(optional<Tp>&& lhs) { + const optional<Tp> rhs; + lhs = rhs; + return !lhs.has_value() && !rhs.has_value(); +} + +template <class Tp> +constexpr bool assign_value(optional<Tp>&& lhs) { + const optional<Tp> rhs(101); + lhs = rhs; + return lhs.has_value() && rhs.has_value() && *lhs == *rhs; +} + +int main() +{ + { + using O = optional<int>; + LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); + LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); + assert(assign_empty(O{42})); + assert(assign_value(O{42})); + } + { + using O = optional<TrivialTestTypes::TestType>; + LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); + LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); + assert(assign_empty(O{42})); + assert(assign_value(O{42})); + } + { + using O = optional<TestTypes::TestType>; + assert(assign_empty(O{42})); + assert(assign_value(O{42})); + } + { + using T = TestTypes::TestType; + T::reset(); + optional<T> opt(3); + const optional<T> opt2; + assert(T::alive == 1); + opt = opt2; + assert(T::alive == 0); + assert(!opt2.has_value()); + assert(!opt.has_value()); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + optional<X> opt; + optional<X> opt2(X{}); + assert(static_cast<bool>(opt2) == true); + try + { + X::throw_now = true; + opt = opt2; + assert(false); + } + catch (int i) + { + assert(i == 6); + assert(static_cast<bool>(opt) == false); + } + } +#endif +} diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp new file mode 100644 index 00000000000..be17aa6fc51 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp @@ -0,0 +1,237 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// <optional> + +// template <class... Args> void optional<T>::emplace(Args&&... args); + +#include <optional> +#include <type_traits> +#include <cassert> +#include <memory> + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; + +class X +{ + int i_; + int j_ = 0; +public: + X() : i_(0) {} + X(int i) : i_(i) {} + X(int i, int j) : i_(i), j_(j) {} + + friend bool operator==(const X& x, const X& y) + {return x.i_ == y.i_ && x.j_ == y.j_;} +}; + +class Y +{ +public: + static bool dtor_called; + Y() = default; + Y(int) { TEST_THROW(6);} + ~Y() {dtor_called = true;} +}; + +bool Y::dtor_called = false; + +template <class T> +void test_one_arg() { + using Opt = std::optional<T>; + { + Opt opt; + opt.emplace(); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(0)); + } + { + Opt opt; + opt.emplace(1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(1)); + } + { + Opt opt(2); + opt.emplace(); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(0)); + } + { + Opt opt(2); + opt.emplace(1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(1)); + } +} + + +template <class T> +void test_multi_arg() +{ + test_one_arg<T>(); + using Opt = std::optional<T>; + Opt opt; + { + opt.emplace(101, 41); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(101, 41)); + } + { + Opt opt; + opt.emplace({1, 2, 3, 4}); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(4)); // T sets its value to the size of the init list + } + { + Opt opt; + opt.emplace({1, 2, 3, 4, 5}, 6); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(5)); // T sets its value to the size of the init list + } +} + +template <class T> +void test_on_test_type() { + + T::reset(); + optional<T> opt; + assert(T::alive == 0); + { + T::reset_constructors(); + opt.emplace(); + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::default_constructed == 1); + assert(T::destroyed == 0); + assert(static_cast<bool>(opt) == true); + assert(*opt == T()); + } + { + T::reset_constructors(); + opt.emplace(); + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::default_constructed == 1); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T()); + } + { + T::reset_constructors(); + opt.emplace(101); + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(101)); + } + { + T::reset_constructors(); + opt.emplace(-10, 99); + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(-10, 99)); + } + { + T::reset_constructors(); + opt.emplace(-10, 99); + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(-10, 99)); + } + { + T::reset_constructors(); + opt.emplace({-10, 99, 42, 1}); + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(4)); // size of the initializer list + } + { + T::reset_constructors(); + opt.emplace({-10, 99, 42, 1}, 42); + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::destroyed == 1); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(4)); // size of the initializer list + } +} + + + +int main() +{ + { + test_on_test_type<TestTypes::TestType>(); + test_on_test_type<ExplicitTestTypes::TestType>(); + } + { + using T = int; + test_one_arg<T>(); + test_one_arg<const T>(); + } + { + using T = ConstexprTestTypes::TestType; + test_multi_arg<T>(); + } + { + using T = ExplicitConstexprTestTypes::TestType; + test_multi_arg<T>(); + } + { + using T = TrivialTestTypes::TestType; + test_multi_arg<T>(); + } + { + using T = ExplicitTrivialTestTypes::TestType; + test_multi_arg<T>(); + } + { + optional<const int> opt; + opt.emplace(42); + assert(*opt == 42); + opt.emplace(); + assert(*opt == 0); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + Y::dtor_called = false; + { + Y y; + optional<Y> opt(y); + try + { + assert(static_cast<bool>(opt) == true); + assert(Y::dtor_called == false); + opt.emplace(1); + } + catch (int i) + { + assert(i == 6); + assert(static_cast<bool>(opt) == false); + assert(Y::dtor_called == true); + } + } +#endif +} diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp new file mode 100644 index 00000000000..1c3c69a7030 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// <optional> + +// template <class U, class... Args> +// void optional<T>::emplace(initializer_list<U> il, Args&&... args); + +#include <optional> +#include <type_traits> +#include <cassert> +#include <vector> + +#include "test_macros.h" + +using std::optional; + +class X +{ + int i_; + int j_ = 0; +public: + static bool dtor_called; + constexpr X() : i_(0) {} + constexpr X(int i) : i_(i) {} + constexpr X(std::initializer_list<int> il) : i_(il.begin()[0]), j_(il.begin()[1]) {} + ~X() {dtor_called = true;} + + friend constexpr bool operator==(const X& x, const X& y) + {return x.i_ == y.i_ && x.j_ == y.j_;} +}; + +bool X::dtor_called = false; + +class Y +{ + int i_; + int j_ = 0; +public: + constexpr Y() : i_(0) {} + constexpr Y(int i) : i_(i) {} + constexpr Y(std::initializer_list<int> il) : i_(il.begin()[0]), j_(il.begin()[1]) {} + + friend constexpr bool operator==(const Y& x, const Y& y) + {return x.i_ == y.i_ && x.j_ == y.j_;} +}; + +class Z +{ + int i_; + int j_ = 0; +public: + static bool dtor_called; + Z() : i_(0) {} + Z(int i) : i_(i) {} + Z(std::initializer_list<int> il) : i_(il.begin()[0]), j_(il.begin()[1]) + { TEST_THROW(6);} + ~Z() {dtor_called = true;} + + friend bool operator==(const Z& x, const Z& y) + {return x.i_ == y.i_ && x.j_ == y.j_;} +}; + +bool Z::dtor_called = false; + +int main() +{ + { + X x; + optional<X> opt(x); + assert(X::dtor_called == false); + opt.emplace({1, 2}); + assert(X::dtor_called == true); + assert(*opt == X({1, 2})); + } + { + optional<std::vector<int>> opt; + opt.emplace({1, 2, 3}, std::allocator<int>()); + assert(static_cast<bool>(opt) == true); + assert(*opt == std::vector<int>({1, 2, 3})); + } + { + optional<Y> opt; + opt.emplace({1, 2}); + assert(static_cast<bool>(opt) == true); + assert(*opt == Y({1, 2})); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + Z z; + optional<Z> opt(z); + try + { + assert(static_cast<bool>(opt) == true); + assert(Z::dtor_called == false); + opt.emplace({1, 2}); + } + catch (int i) + { + assert(i == 6); + assert(static_cast<bool>(opt) == false); + assert(Z::dtor_called == true); + } + } +#endif +} diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp new file mode 100644 index 00000000000..3ba261b5246 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp @@ -0,0 +1,174 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// <optional> + +// optional<T>& operator=(optional<T>&& rhs) +// noexcept(is_nothrow_move_assignable<T>::value && +// is_nothrow_move_constructible<T>::value); + +#include <optional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; + +struct X +{ + static bool throw_now; + static int alive; + + X() { ++alive; } + X(X&&) + { + if (throw_now) + TEST_THROW(6); + ++alive; + } + + X& operator=(X&&) + { + if (throw_now) + TEST_THROW(42); + return *this; + } + + ~X() { assert(alive > 0); --alive; } +}; + +struct Y {}; + +bool X::throw_now = false; +int X::alive = 0; + +int main() +{ + { + static_assert(std::is_nothrow_move_assignable<optional<int>>::value, ""); + optional<int> opt; + constexpr optional<int> opt2; + opt = std::move(opt2); + static_assert(static_cast<bool>(opt2) == false, ""); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + } + { + optional<int> opt; + constexpr optional<int> opt2(2); + opt = std::move(opt2); + static_assert(static_cast<bool>(opt2) == true, ""); + static_assert(*opt2 == 2, ""); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + assert(*opt == *opt2); + } + { + optional<int> opt(3); + constexpr optional<int> opt2; + opt = std::move(opt2); + static_assert(static_cast<bool>(opt2) == false, ""); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + } + { + using T = TestTypes::TestType; + T::reset(); + optional<T> opt(3); + optional<T> opt2; + assert(T::alive == 1); + opt = std::move(opt2); + assert(T::alive == 0); + assert(static_cast<bool>(opt2) == false); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + } + { + optional<int> opt(3); + constexpr optional<int> opt2(2); + opt = std::move(opt2); + static_assert(static_cast<bool>(opt2) == true, ""); + static_assert(*opt2 == 2, ""); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + assert(*opt == *opt2); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, ""); + X::alive = 0; + X::throw_now = false; + optional<X> opt; + optional<X> opt2(X{}); + assert(X::alive == 1); + assert(static_cast<bool>(opt2) == true); + try + { + X::throw_now = true; + opt = std::move(opt2); + assert(false); + } + catch (int i) + { + assert(i == 6); + assert(static_cast<bool>(opt) == false); + } + assert(X::alive == 1); + } + assert(X::alive == 0); + { + static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, ""); + X::throw_now = false; + optional<X> opt(X{}); + optional<X> opt2(X{}); + assert(X::alive == 2); + assert(static_cast<bool>(opt2) == true); + try + { + X::throw_now = true; + opt = std::move(opt2); + assert(false); + } + catch (int i) + { + assert(i == 42); + assert(static_cast<bool>(opt) == true); + } + assert(X::alive == 2); + } + assert(X::alive == 0); +#endif // TEST_HAS_NO_EXCEPTIONS + { + static_assert(std::is_nothrow_move_assignable<optional<Y>>::value, ""); + } + { + struct ThrowsMove { + ThrowsMove() noexcept {} + ThrowsMove(ThrowsMove const&) noexcept {} + ThrowsMove(ThrowsMove &&) noexcept(false) {} + ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; } + ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; } + }; + static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, ""); + struct ThrowsMoveAssign { + ThrowsMoveAssign() noexcept {} + ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {} + ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {} + ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; } + ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; } + }; + static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, ""); + struct NoThrowMove { + NoThrowMove() noexcept(false) {} + NoThrowMove(NoThrowMove const&) noexcept(false) {} + NoThrowMove(NoThrowMove &&) noexcept {} + NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; } + NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; } + }; + static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, ""); + } +} diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp new file mode 100644 index 00000000000..991f4334304 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// <optional> + +// optional<T>& operator=(nullopt_t) noexcept; + +#include <optional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; +using std::nullopt_t; +using std::nullopt; + +int main() +{ + { + optional<int> opt; + static_assert(noexcept(opt = nullopt) == true, ""); + opt = nullopt; + assert(static_cast<bool>(opt) == false); + } + { + optional<int> opt(3); + opt = nullopt; + assert(static_cast<bool>(opt) == false); + } + using TT = TestTypes::TestType; + TT::reset(); + { + optional<TT> opt; + static_assert(noexcept(opt = nullopt) == true, ""); + assert(TT::destroyed == 0); + opt = nullopt; + assert(TT::constructed == 0); + assert(TT::alive == 0); + assert(TT::destroyed == 0); + assert(static_cast<bool>(opt) == false); + } + assert(TT::alive == 0); + assert(TT::destroyed == 0); + TT::reset(); + { + optional<TT> opt(42); + assert(TT::destroyed == 0); + TT::reset_constructors(); + opt = nullopt; + assert(TT::constructed == 0); + assert(TT::alive == 0); + assert(TT::destroyed == 1); + assert(static_cast<bool>(opt) == false); + } + assert(TT::alive == 0); + assert(TT::destroyed == 1); + TT::reset(); +} diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp new file mode 100644 index 00000000000..db7fc19bfb1 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp @@ -0,0 +1,268 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// <optional> + +// From LWG2451: +// template <class U> +// optional<T>& operator=(optional<U>&& rhs); + +#include <optional> +#include <type_traits> +#include <memory> +#include <cassert> + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; + +struct X +{ + static bool throw_now; + + X() = default; + X(int &&) + { + if (throw_now) + TEST_THROW(6); + } +}; + +bool X::throw_now = false; + +struct Y1 +{ + Y1() = default; + Y1(const int&) {} + Y1& operator=(const Y1&) = delete; +}; + +struct Y2 +{ + Y2() = default; + Y2(const int&) = delete; + Y2& operator=(const int&) { return *this; } +}; + +class B {}; +class D : public B {}; + + +template <class T> +struct AssignableFrom { + static int type_constructed; + static int type_assigned; +static int int_constructed; + static int int_assigned; + + static void reset() { + type_constructed = int_constructed = 0; + type_assigned = int_assigned = 0; + } + + AssignableFrom() = default; + + explicit AssignableFrom(T) { ++type_constructed; } + AssignableFrom& operator=(T) { ++type_assigned; return *this; } + + AssignableFrom(int) { ++int_constructed; } + AssignableFrom& operator=(int) { ++int_assigned; return *this; } +private: + AssignableFrom(AssignableFrom const&) = delete; + AssignableFrom& operator=(AssignableFrom const&) = delete; +}; + +template <class T> int AssignableFrom<T>::type_constructed = 0; +template <class T> int AssignableFrom<T>::type_assigned = 0; +template <class T> int AssignableFrom<T>::int_constructed = 0; +template <class T> int AssignableFrom<T>::int_assigned = 0; + +void test_with_test_type() { + using T = TestTypes::TestType; + T::reset(); + { // non-empty to empty + T::reset_constructors(); + optional<T> opt; + optional<int> other(42); + opt = std::move(other); + assert(T::alive == 1); + assert(T::constructed == 1); + assert(T::value_constructed == 1); + assert(T::assigned == 0); + assert(T::destroyed == 0); + assert(static_cast<bool>(other) == true); + assert(*other == 42); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(42)); + } + assert(T::alive == 0); + { // non-empty to non-empty + optional<T> opt(101); + optional<int> other(42); + T::reset_constructors(); + opt = std::move(other); + assert(T::alive == 1); + assert(T::constructed == 0); + assert(T::assigned == 1); + assert(T::value_assigned == 1); + assert(T::destroyed == 0); + assert(static_cast<bool>(other) == true); + assert(*other == 42); + assert(static_cast<bool>(opt) == true); + assert(*opt == T(42)); + } + assert(T::alive == 0); + { // empty to non-empty + optional<T> opt(101); + optional<int> other; + T::reset_constructors(); + opt = std::move(other); + assert(T::alive == 0); + assert(T::constructed == 0); + assert(T::assigned == 0); + assert(T::destroyed == 1); + assert(static_cast<bool>(other) == false); + assert(static_cast<bool>(opt) == false); + } + assert(T::alive == 0); + { // empty to empty + optional<T> opt; + optional<int> other; + T::reset_constructors(); + opt = std::move(other); + assert(T::alive == 0); + assert(T::constructed == 0); + assert(T::assigned == 0); + assert(T::destroyed == 0); + assert(static_cast<bool>(other) == false); + assert(static_cast<bool>(opt) == false); + } + assert(T::alive == 0); +} + + +void test_ambigious_assign() { + using OptInt = std::optional<int>; + { + using T = AssignableFrom<OptInt&&>; + T::reset(); + { + OptInt a(42); + std::optional<T> t; + t = std::move(a); + assert(T::type_constructed == 1); + assert(T::type_assigned == 0); + assert(T::int_constructed == 0); + assert(T::int_assigned == 0); + } + { + using Opt = std::optional<T>; + static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, ""); + static_assert(!std::is_assignable<Opt&, const OptInt&>::value, ""); + static_assert(!std::is_assignable<Opt&, OptInt&>::value, ""); + } + } + { + using T = AssignableFrom<OptInt const&&>; + T::reset(); + { + const OptInt a(42); + std::optional<T> t; + t = std::move(a); + assert(T::type_constructed == 1); + assert(T::type_assigned == 0); + assert(T::int_constructed == 0); + assert(T::int_assigned == 0); + } + T::reset(); + { + OptInt a(42); + std::optional<T> t; + t = std::move(a); + assert(T::type_constructed == 1); + assert(T::type_assigned == 0); + assert(T::int_constructed == 0); + assert(T::int_assigned == 0); + } + { + using Opt = std::optional<T>; + static_assert(std::is_assignable<Opt&, OptInt&&>::value, ""); + static_assert(!std::is_assignable<Opt&, const OptInt&>::value, ""); + static_assert(!std::is_assignable<Opt&, OptInt&>::value, ""); + } + } +} + + +int main() +{ + test_with_test_type(); + test_ambigious_assign(); + { + optional<int> opt; + optional<short> opt2; + opt = std::move(opt2); + assert(static_cast<bool>(opt2) == false); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + } + { + optional<int> opt; + optional<short> opt2(short{2}); + opt = std::move(opt2); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + assert(*opt == *opt2); + } + { + optional<int> opt(3); + optional<short> opt2; + opt = std::move(opt2); + assert(static_cast<bool>(opt2) == false); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + } + { + optional<int> opt(3); + optional<short> opt2(short{2}); + opt = std::move(opt2); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); + assert(*opt == *opt2); + } + { + optional<std::unique_ptr<B>> opt; + optional<std::unique_ptr<D>> other(new D()); + opt = std::move(other); + assert(static_cast<bool>(opt) == true); + assert(static_cast<bool>(other) == true); + assert(opt->get() != nullptr); + assert(other->get() == nullptr); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + optional<X> opt; + optional<int> opt2(42); + assert(static_cast<bool>(opt2) == true); + try + { + X::throw_now = true; + opt = std::move(opt2); + assert(false); + } + catch (int i) + { + assert(i == 6); + assert(static_cast<bool>(opt) == false); + } + } +#endif +} |