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.specalg | |
| 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.specalg')
4 files changed, 501 insertions, 0 deletions
diff --git a/libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp b/libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp new file mode 100644 index 00000000000..3fbf19f8ee1 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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 T> +// constexpr optional<decay_t<T>> make_optional(T&& v); + +#include <optional> +#include <string> +#include <memory> +#include <cassert> + +#include "test_macros.h" + +int main() +{ + using std::optional; + using std::make_optional; + { + int arr[10]; ((void)arr); + ASSERT_SAME_TYPE(decltype(make_optional(arr)), optional<int*>); + } + { + constexpr auto opt = make_optional(2); + ASSERT_SAME_TYPE(decltype(opt), const optional<int>); + static_assert(opt.value() == 2); + } + { + optional<int> opt = make_optional(2); + assert(*opt == 2); + } + { + std::string s("123"); + optional<std::string> opt = make_optional(s); + assert(*opt == s); + } + { + std::unique_ptr<int> s(new int(3)); + optional<std::unique_ptr<int>> opt = make_optional(std::move(s)); + assert(**opt == 3); + assert(s == nullptr); + } +} diff --git a/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp b/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp new file mode 100644 index 00000000000..bdfeefbcc1d --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 T, class... Args> +// constexpr optional<T> make_optional(Args&&... args); + +#include <optional> +#include <string> +#include <memory> +#include <cassert> + +int main() +{ + using std::optional; + using std::make_optional; + + { + constexpr auto opt = make_optional<int>('a'); + static_assert(*opt == int('a'), ""); + } + { + std::string s("123"); + auto opt = make_optional<std::string>(s); + assert(*opt == s); + } + { + std::unique_ptr<int> s(new int(3)); + auto opt = make_optional<std::unique_ptr<int>>(std::move(s)); + assert(**opt == 3); + assert(s == nullptr); + } + { + auto opt = make_optional<std::string>(4, 'X'); + assert(*opt == "XXXX"); + } +} diff --git a/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit_initializer_list.pass.cpp b/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit_initializer_list.pass.cpp new file mode 100644 index 00000000000..f17f5820d20 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit_initializer_list.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 T, class U, class... Args> +// constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args); + +#include <optional> +#include <string> +#include <memory> +#include <cassert> + +#include "test_macros.h" + +struct TestT { + int x; + int size; + constexpr TestT(std::initializer_list<int> il) : x(*il.begin()), size(il.size()) {} + constexpr TestT(std::initializer_list<int> il, const int*) + : x(*il.begin()), size(il.size()) {} +}; + +int main() +{ + using std::make_optional; + { + constexpr auto opt = make_optional<TestT>({42, 2, 3}); + ASSERT_SAME_TYPE(decltype(opt), const std::optional<TestT>); + static_assert(opt->x == 42, ""); + static_assert(opt->size == 3, ""); + } + { + constexpr auto opt = make_optional<TestT>({42, 2, 3}, nullptr); + static_assert(opt->x == 42, ""); + static_assert(opt->size == 3, ""); + } + { + auto opt = make_optional<std::string>({'1', '2', '3'}); + assert(*opt == "123"); + } + { + auto opt = make_optional<std::string>({'a', 'b', 'c'}, std::allocator<char>{}); + assert(*opt == "abc"); + } +} diff --git a/libcxx/test/std/utilities/optional/optional.specalg/swap.pass.cpp b/libcxx/test/std/utilities/optional/optional.specalg/swap.pass.cpp new file mode 100644 index 00000000000..9f1d0305022 --- /dev/null +++ b/libcxx/test/std/utilities/optional/optional.specalg/swap.pass.cpp @@ -0,0 +1,352 @@ +//===----------------------------------------------------------------------===// +// +// 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 T> void swap(optional<T>& x, optional<T>& y) +// noexcept(noexcept(x.swap(y))); + +#include <optional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; + +class X +{ + int i_; +public: + static unsigned dtor_called; + X(int i) : i_(i) {} + X(X&& x) = default; + X& operator=(X&&) = default; + ~X() {++dtor_called;} + + friend bool operator==(const X& x, const X& y) {return x.i_ == y.i_;} +}; + +unsigned X::dtor_called = 0; + +class Y +{ + int i_; +public: + static unsigned dtor_called; + Y(int i) : i_(i) {} + Y(Y&&) = default; + ~Y() {++dtor_called;} + + friend constexpr bool operator==(const Y& x, const Y& y) {return x.i_ == y.i_;} + friend void swap(Y& x, Y& y) {std::swap(x.i_, y.i_);} +}; + +unsigned Y::dtor_called = 0; + +class Z +{ + int i_; +public: + Z(int i) : i_(i) {} + Z(Z&&) { TEST_THROW(7);} + + friend constexpr bool operator==(const Z& x, const Z& y) {return x.i_ == y.i_;} + friend void swap(Z& x, Z& y) { TEST_THROW(6);} +}; + + +struct NonSwappable { + NonSwappable(NonSwappable const&) = delete; +}; +void swap(NonSwappable&, NonSwappable&) = delete; + +void test_swap_sfinae() { + using std::optional; + { + using T = TestTypes::TestType; + static_assert(std::is_swappable_v<optional<T>>, ""); + } + { + using T = TestTypes::MoveOnly; + static_assert(std::is_swappable_v<optional<T>>, ""); + } + { + using T = TestTypes::Copyable; + static_assert(std::is_swappable_v<optional<T>>, ""); + } + { + using T = TestTypes::NoCtors; + static_assert(!std::is_swappable_v<optional<T>>, ""); + } + { + using T = NonSwappable; + static_assert(!std::is_swappable_v<optional<T>>, ""); + } + { + // Even thought CopyOnly has deleted move operations, those operations + // cause optional<CopyOnly> to have implicitly deleted move operations + // that decay into copies. + using T = TestTypes::CopyOnly; + using Opt = optional<T>; + T::reset(); + Opt L(101), R(42); + T::reset_constructors(); + std::swap(L, R); + assert(L->value == 42); + assert(R->value == 101); + assert(T::copy_constructed == 1); + assert(T::constructed == T::copy_constructed); + assert(T::assigned == 2); + assert(T::assigned == T::copy_assigned); + } +} + +int main() +{ + test_swap_sfinae(); + { + optional<int> opt1; + optional<int> opt2; + static_assert(noexcept(swap(opt1, opt2)) == true, ""); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == false); + swap(opt1, opt2); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == false); + } + { + optional<int> opt1(1); + optional<int> opt2; + static_assert(noexcept(swap(opt1, opt2)) == true, ""); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == false); + swap(opt1, opt2); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 1); + } + { + optional<int> opt1; + optional<int> opt2(2); + static_assert(noexcept(swap(opt1, opt2)) == true, ""); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + swap(opt1, opt2); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 2); + assert(static_cast<bool>(opt2) == false); + } + { + optional<int> opt1(1); + optional<int> opt2(2); + static_assert(noexcept(swap(opt1, opt2)) == true, ""); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + swap(opt1, opt2); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 2); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 1); + } + { + optional<X> opt1; + optional<X> opt2; + static_assert(noexcept(swap(opt1, opt2)) == true, ""); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == false); + swap(opt1, opt2); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == false); + assert(X::dtor_called == 0); + } + { + optional<X> opt1(1); + optional<X> opt2; + static_assert(noexcept(swap(opt1, opt2)) == true, ""); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == false); + X::dtor_called = 0; + swap(opt1, opt2); + assert(X::dtor_called == 1); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 1); + } + { + optional<X> opt1; + optional<X> opt2(2); + static_assert(noexcept(swap(opt1, opt2)) == true, ""); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + X::dtor_called = 0; + swap(opt1, opt2); + assert(X::dtor_called == 1); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 2); + assert(static_cast<bool>(opt2) == false); + } + { + optional<X> opt1(1); + optional<X> opt2(2); + static_assert(noexcept(swap(opt1, opt2)) == true, ""); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + X::dtor_called = 0; + swap(opt1, opt2); + assert(X::dtor_called == 1); // from inside std::swap + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 2); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 1); + } + { + optional<Y> opt1; + optional<Y> opt2; + static_assert(noexcept(swap(opt1, opt2)) == false, ""); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == false); + swap(opt1, opt2); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == false); + assert(Y::dtor_called == 0); + } + { + optional<Y> opt1(1); + optional<Y> opt2; + static_assert(noexcept(swap(opt1, opt2)) == false, ""); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == false); + Y::dtor_called = 0; + swap(opt1, opt2); + assert(Y::dtor_called == 1); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 1); + } + { + optional<Y> opt1; + optional<Y> opt2(2); + static_assert(noexcept(swap(opt1, opt2)) == false, ""); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + Y::dtor_called = 0; + swap(opt1, opt2); + assert(Y::dtor_called == 1); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 2); + assert(static_cast<bool>(opt2) == false); + } + { + optional<Y> opt1(1); + optional<Y> opt2(2); + static_assert(noexcept(swap(opt1, opt2)) == false, ""); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + Y::dtor_called = 0; + swap(opt1, opt2); + assert(Y::dtor_called == 0); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 2); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 1); + } + { + optional<Z> opt1; + optional<Z> opt2; + static_assert(noexcept(swap(opt1, opt2)) == false, ""); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == false); + swap(opt1, opt2); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == false); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + optional<Z> opt1; + opt1.emplace(1); + optional<Z> opt2; + static_assert(noexcept(swap(opt1, opt2)) == false, ""); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == false); + try + { + swap(opt1, opt2); + assert(false); + } + catch (int i) + { + assert(i == 7); + } + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == false); + } + { + optional<Z> opt1; + optional<Z> opt2; + opt2.emplace(2); + static_assert(noexcept(swap(opt1, opt2)) == false, ""); + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + try + { + swap(opt1, opt2); + assert(false); + } + catch (int i) + { + assert(i == 7); + } + assert(static_cast<bool>(opt1) == false); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + } + { + optional<Z> opt1; + opt1.emplace(1); + optional<Z> opt2; + opt2.emplace(2); + static_assert(noexcept(swap(opt1, opt2)) == false, ""); + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + try + { + swap(opt1, opt2); + assert(false); + } + catch (int i) + { + assert(i == 6); + } + assert(static_cast<bool>(opt1) == true); + assert(*opt1 == 1); + assert(static_cast<bool>(opt2) == true); + assert(*opt2 == 2); + } +#endif // TEST_HAS_NO_EXCEPTIONS +} |

