diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -318,6 +318,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_typeinfo`` *unimplemented* ------------------------------------------------- ----------------- + ``__cpp_lib_expected`` ``202202L`` + ------------------------------------------------- ----------------- ``__cpp_lib_forward_like`` ``202207L`` ------------------------------------------------- ----------------- ``__cpp_lib_invoke_r`` *unimplemented* diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -167,11 +167,11 @@ "`3671 `__","``atomic_fetch_xor`` missing from ``stdatomic.h``","July 2022","","" "`3672 `__","``common_iterator::operator->()`` should return by value","July 2022","","","|ranges|" "`3683 `__","``operator==`` for ``polymorphic_allocator`` cannot deduce template argument in common cases","July 2022","","" -"`3687 `__","``expected`` move constructor should move","July 2022","","" +"`3687 `__","``expected`` move constructor should move","July 2022","Complete","16.0" "`3692 `__","``zip_view::iterator``'s ``operator<=>`` is overconstrained","July 2022","","","|spaceship|" "`3701 `__","Make ``formatter, charT>`` requirement explicit","July 2022","","","|format|" "`3702 `__","Should ``zip_transform_view::iterator`` remove ``operator<``","July 2022","","" -"`3703 `__","Missing requirements for ``expected`` requires ``is_void``","July 2022","","" +"`3703 `__","Missing requirements for ``expected`` requires ``is_void``","July 2022","Complete","16.0" "`3704 `__","LWG 2059 added overloads that might be ill-formed for sets","July 2022","","" "`3705 `__","Hashability shouldn't depend on basic_string's allocator","July 2022","|Complete|","16.0" "`3707 `__","chunk_view::outer-iterator::value_type::size should return unsigned type","July 2022","","","|ranges|" diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -38,7 +38,7 @@ "`P2393R1 `__","LWG","Cleaning up ``integer``-class types","October 2021","","" "`P2401R0 `__","LWG","Add a conditional ``noexcept`` specification to ``std::exchange``","October 2021","|Complete|","14.0" "","","","","","" -"`P0323R12 `__","LWG","``std::expected``","February 2022","","" +"`P0323R12 `__","LWG","``std::expected``","February 2022","|Complete|","16.0" "`P0533R9 `__","LWG","``constexpr`` for ```` and ````","February 2022","","" "`P0627R6 `__","LWG","Function to mark unreachable code","February 2022","|Complete|","15.0" "`P1206R7 `__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","","" @@ -86,7 +86,7 @@ "`P2517R1 `__","LWG","Add a conditional ``noexcept`` specification to ``std::apply``","July 2022","","" "`P2520R0 `__","LWG","``move_iterator`` should be a random access iterator","July 2022","","" "`P2540R1 `__","LWG","Empty Product for certain Views","July 2022","","" -"`P2549R1 `__","LWG","``std::unexpected`` should have ``error()`` as member accessor","July 2022","","" +"`P2549R1 `__","LWG","``std::unexpected`` should have ``error()`` as member accessor","July 2022","|Complete|","16.0" "`P2553R1 `__","LWG","Make ``mdspan`` ``size_type`` controllable","July 2022","","" "`P2554R0 `__","LWG","C-Array Interoperability of MDSpan","July 2022","","" "`P2585R0 `__","LWG","Improving default container formatting","July 2022","","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -269,6 +269,10 @@ __debug __debug_utils/randomize_range.h __errc + __expected/bad_expected_access.h + __expected/expected.h + __expected/unexpect.h + __expected/unexpected.h __filesystem/copy_options.h __filesystem/directory_entry.h __filesystem/directory_iterator.h @@ -738,6 +742,7 @@ errno.h exception execution + expected experimental/__config experimental/__memory experimental/algorithm diff --git a/libcxx/include/__expected/bad_expected_access.h b/libcxx/include/__expected/bad_expected_access.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__expected/bad_expected_access.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H +#define _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H + +#include <__config> +#include <__utility/move.h> + +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class bad_expected_access; + +template <> +class bad_expected_access : public exception { +protected: + _LIBCPP_HIDE_FROM_ABI bad_expected_access() noexcept = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access(const bad_expected_access&) = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access(bad_expected_access&&) = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(const bad_expected_access&) = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(bad_expected_access&&) = default; + ~bad_expected_access() override = default; + +public: + // The way this has been designed (by using a class template below) means that we'll already + // have a profusion of these vtables in TUs, and the dynamic linker will already have a bunch + // of work to do. So it is not worth hiding the specialization in the dylib, given that + // it adds deployment target restrictions. + const char* what() const noexcept override { return "bad access to std::expected"; } +}; + +template +class bad_expected_access : public bad_expected_access { +public: + _LIBCPP_HIDE_FROM_ABI explicit bad_expected_access(_Err __e) : __unex_(std::move(__e)) {} + + _LIBCPP_HIDE_FROM_ABI _Err& error() & noexcept { return __unex_; } + _LIBCPP_HIDE_FROM_ABI const _Err& error() const& noexcept { return __unex_; } + _LIBCPP_HIDE_FROM_ABI _Err&& error() && noexcept { return std::move(__unex_); } + _LIBCPP_HIDE_FROM_ABI const _Err&& error() const&& noexcept { return std::move(__unex_); } + +private: + _Err __unex_; +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__expected/expected.h @@ -0,0 +1,936 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___EXPECTED_EXPECTED_H +#define _LIBCPP___EXPECTED_EXPECTED_H + +#include <__assert> +#include <__config> +#include <__expected/bad_expected_access.h> +#include <__expected/unexpect.h> +#include <__expected/unexpected.h> +#include <__memory/addressof.h> +#include <__memory/construct_at.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/disjunction.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_copy_assignable.h> +#include <__type_traits/is_copy_constructible.h> +#include <__type_traits/is_default_constructible.h> +#include <__type_traits/is_function.h> +#include <__type_traits/is_move_assignable.h> +#include <__type_traits/is_move_constructible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_nothrow_copy_assignable.h> +#include <__type_traits/is_nothrow_copy_constructible.h> +#include <__type_traits/is_nothrow_default_constructible.h> +#include <__type_traits/is_nothrow_move_assignable.h> +#include <__type_traits/is_nothrow_move_constructible.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_swappable.h> +#include <__type_traits/is_trivially_copy_constructible.h> +#include <__type_traits/is_trivially_destructible.h> +#include <__type_traits/is_trivially_move_constructible.h> +#include <__type_traits/is_void.h> +#include <__type_traits/lazy.h> +#include <__type_traits/negation.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/swap.h> +#include <__utility/transaction.h> +#include + +#ifdef _LIBCPP_NO_EXCEPTIONS +# include // for std::abort +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __expected { + +template +_LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) { +# ifndef _LIBCPP_NO_EXCEPTIONS + throw bad_expected_access<_Err>(std::forward<_Arg>(__arg)); +# else + (void)__arg; + std::abort(); +# endif +} + +} // namespace __expected + +template +class expected { + static_assert( + !is_reference_v<_Tp> && // + !is_function_v<_Tp> && // + !is_same_v, in_place_t> && // + !is_same_v, unexpect_t> && // + !__unexpected::__is_unexpected>::value && // + __unexpected::__valid_unexpected<_Err>::value // + , + "[expected.object.general] A program that instantiates the definition of template expected for a " + "reference type, a function type, or for possibly cv-qualified types in_place_t, unexpect_t, or a " + "specialization of unexpected for the T parameter is ill-formed. A program that instantiates the " + "definition of the template expected with a type for the E parameter that is not a valid " + "template argument for unexpected is ill-formed."); + + template + friend class expected; + +public: + using value_type = _Tp; + using error_type = _Err; + using unexpected_type = unexpected<_Err>; + + template + using rebind = expected<_Up, error_type>; + + // [expected.object.ctor], constructors + _LIBCPP_HIDE_FROM_ABI constexpr expected() // + noexcept(is_nothrow_default_constructible_v<_Tp>) + requires is_default_constructible_v<_Tp> + : __val_(), __has_val_(true) {} + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) + requires(is_copy_constructible_v<_Tp> && // + is_copy_constructible_v<_Err> && // + is_trivially_copy_constructible_v<_Tp> && // + is_trivially_copy_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __other) // + noexcept(is_nothrow_copy_constructible_v<_Tp>&& // + is_nothrow_copy_constructible_v<_Err>) + requires(is_copy_constructible_v<_Tp> && // + is_copy_constructible_v<_Err> && // + !(is_trivially_copy_constructible_v<_Tp> && // + is_trivially_copy_constructible_v<_Err>)) + : __has_val_(__other.__has_val_) { + if (__has_val_) { + std::construct_at(std::addressof(__val_), __other.__val_); + } else { + std::construct_at(std::addressof(__unex_), __other.__unex_); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&) + requires(is_move_constructible_v<_Tp> && // + is_move_constructible_v<_Err> && // + is_trivially_move_constructible_v<_Tp> && // + is_trivially_move_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __other) // + noexcept(is_nothrow_move_constructible_v<_Tp>&& // + is_nothrow_move_constructible_v<_Err>) + requires(is_move_constructible_v<_Tp> && // + is_move_constructible_v<_Err> && // + !(is_trivially_move_constructible_v<_Tp> && // + is_trivially_move_constructible_v<_Err>)) + : __has_val_(__other.__has_val_) { + if (__has_val_) { + std::construct_at(std::addressof(__val_), std::move(__other.__val_)); + } else { + std::construct_at(std::addressof(__unex_), std::move(__other.__unex_)); + } + } + +private: + template + using __can_convert = _And< // + is_constructible<_Tp, _Uf>, // + is_constructible<_Err, _Gf>, // + _Not&>>, // + _Not>>, // + _Not&>>, // + _Not>>, // + _Not&, _Tp>>, // + _Not&&, _Tp>>, // + _Not&, _Tp>>, // + _Not&&, _Tp>>, // + _Not, expected<_Up, _Gp>&>>, // + _Not, expected<_Up, _Gp>>>, // + _Not, const expected<_Up, _Gp>&>>, // + _Not, const expected<_Up, _Gp>>> // + >; + +public: + template + requires __can_convert<_Up, _Gp, const _Up&, const _Gp&>::value + _LIBCPP_HIDE_FROM_ABI constexpr // + explicit(!is_convertible_v || // + !is_convertible_v) // + expected(const expected<_Up, _Gp>& __other) // + noexcept((is_nothrow_constructible_v<_Tp, const _Up&> && // + is_nothrow_constructible_v<_Err, const _Gp&>)) + : __has_val_(__other.__has_val_) { + if (__has_val_) { + std::construct_at(std::addressof(__val_), __other.__val_); + } else { + std::construct_at(std::addressof(__unex_), __other.__unex_); + } + } + + template + requires __can_convert<_Up, _Gp, _Up, _Gp>::value + _LIBCPP_HIDE_FROM_ABI constexpr // + explicit(!is_convertible_v<_Up, _Tp> || // + !is_convertible_v<_Gp, _Err>) // + expected(expected<_Up, _Gp>&& __other) // + noexcept(is_nothrow_constructible_v<_Tp, _Up>&& // + is_nothrow_constructible_v<_Err, _Gp>) + : __has_val_(__other.__has_val_) { + if (__has_val_) { + std::construct_at(std::addressof(__val_), std::move(__other.__val_)); + } else { + std::construct_at(std::addressof(__unex_), std::move(__other.__unex_)); + } + } + + template + requires(!is_same_v, in_place_t> && // + !is_same_v> && // + !__unexpected::__is_unexpected>::value && // + is_constructible_v<_Tp, _Up>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>) expected(_Up&& __u) // + noexcept(is_nothrow_constructible_v<_Tp, _Up>) + : __val_(std::forward<_Up>(__u)), __has_val_(true) {} + + template + requires is_constructible_v<_Err, const _Gp&> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) + expected(const unexpected<_Gp>& __unex) // + noexcept(is_nothrow_constructible_v<_Err, const _Gp&>) + : __unex_(__unex.error()), __has_val_(false) {} + + template + requires is_constructible_v<_Err, _Gp> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Gp, _Err>) // + expected(unexpected<_Gp>&& __unex) // + noexcept(is_nothrow_constructible_v<_Err, _Gp>) + : __unex_(std::move(__unex.error())), __has_val_(false) {} + + template + requires is_constructible_v<_Tp, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args) // + noexcept(is_nothrow_constructible_v<_Tp, _Args...>) + : __val_(std::forward<_Args>(__args)...), __has_val_(true) {} + + template + requires is_constructible_v< _Tp, initializer_list<_Up>&, _Args... > + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) // + noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) + : __val_(__il, std::forward<_Args>(__args)...), __has_val_(true) {} + + template + requires is_constructible_v<_Err, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) // + noexcept(is_nothrow_constructible_v<_Err, _Args...>) + : __unex_(std::forward<_Args>(__args)...), __has_val_(false) {} + + template + requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... > + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) + : __unex_(__il, std::forward<_Args>(__args)...), __has_val_(false) {} + + // [expected.object.dtor], destructor + + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() + requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() + requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>) + { + if (__has_val_) { + std::destroy_at(std::addressof(__val_)); + } else { + std::destroy_at(std::addressof(__unex_)); + } + } + +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr void __reinit_expected(_T1& __newval, _T2& __oldval, _Args&&... __args) { + if constexpr (is_nothrow_constructible_v<_T1, _Args...>) { + std::destroy_at(std::addressof(__oldval)); + std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...); + } else if constexpr (is_nothrow_move_constructible_v<_T1>) { + _T1 __tmp(std::forward<_Args>(__args)...); + std::destroy_at(std::addressof(__oldval)); + std::construct_at(std::addressof(__newval), std::move(__tmp)); + } else { + static_assert( + is_nothrow_move_constructible_v<_T2>, + "To provide strong exception guarrentee, T2 has to satisfy `is_nothrow_move_constructible_v` so that it can " + "be reverted to the previous state in case an exception is thrown during the assignment."); + _T2 __tmp(std::move(__oldval)); + std::destroy_at(std::addressof(__oldval)); + __transaction __trans([&] { std::construct_at(std::addressof(__oldval), std::move(__tmp)); }); + std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...); + __trans.__complete(); + } + } + +public: + // [expected.object.assign], assignment + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) // + noexcept((is_nothrow_copy_assignable_v<_Tp> && // + is_nothrow_copy_constructible_v<_Tp> && // + is_nothrow_copy_assignable_v<_Err> && // + is_nothrow_copy_constructible_v<_Err>)) + requires(is_copy_assignable_v<_Tp> && // + is_copy_constructible_v<_Tp> && // + is_copy_assignable_v<_Err> && // + is_copy_constructible_v<_Err> && // + (is_nothrow_move_constructible_v<_Tp> || // + is_nothrow_move_constructible_v<_Err>)) + { + if (__has_val_ && __rhs.__has_val_) { + __val_ = __rhs.__val_; + } else if (__has_val_) { + __reinit_expected(__unex_, __val_, __rhs.__unex_); + } else if (__rhs.__has_val_) { + __reinit_expected(__val_, __unex_, __rhs.__val_); + } else { + __unex_ = __rhs.__unex_; + } + // note: only reached if no exception+rollback was done inside __reinit_expected + __has_val_ = __rhs.__has_val_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs) // + noexcept((is_nothrow_move_assignable_v<_Tp> && // + is_nothrow_move_constructible_v<_Tp> && // + is_nothrow_move_assignable_v<_Err> && // + is_nothrow_move_constructible_v<_Err>)) + requires(is_move_constructible_v<_Tp> && // + is_move_assignable_v<_Tp> && // + is_move_constructible_v<_Err> && // + is_move_assignable_v<_Err> && // + (is_nothrow_move_constructible_v<_Tp> || // + is_nothrow_move_constructible_v<_Err>)) + { + if (__has_val_ && __rhs.__has_val_) { + __val_ = std::move(__rhs.__val_); + } else if (__has_val_) { + __reinit_expected(__unex_, __val_, std::move(__rhs.__unex_)); + } else if (__rhs.__has_val_) { + __reinit_expected(__val_, __unex_, std::move(__rhs.__val_)); + } else { + __unex_ = std::move(__rhs.__unex_); + } + // note: only reached if no exception+rollback was done inside __reinit_expected + __has_val_ = __rhs.__has_val_; + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(_Up&& __v) + requires(!is_same_v> && // + !__unexpected::__is_unexpected>::value && // + is_constructible_v<_Tp, _Up> && // + is_assignable_v<_Tp&, _Up> && // + (is_nothrow_constructible_v<_Tp, _Up> || // + is_nothrow_move_constructible_v<_Tp> || // + is_nothrow_move_constructible_v<_Err>)) + { + if (__has_val_) { + __val_ = std::forward<_Up>(__v); + } else { + __reinit_expected(__val_, __unex_, std::forward<_Up>(__v)); + __has_val_ = true; + } + return *this; + } + +private: + template + static constexpr bool __can_assign_from_unexpected = _And< // + is_constructible<_Err, _Gf>, // + is_assignable<_Err&, _Gf>, // + _Lazy<_Or, + is_nothrow_constructible<_Err, _Gf>, // + is_nothrow_move_constructible<_Tp>, // + is_nothrow_move_constructible<_Err>> // + >::value; + +public: + template + requires(__can_assign_from_unexpected) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_Gp>& __un) { + if (__has_val_) { + __reinit_expected(__unex_, __val_, __un.error()); + __has_val_ = false; + } else { + __unex_ = __un.error(); + } + return *this; + } + + template + requires(__can_assign_from_unexpected<_Gp>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_Gp>&& __un) { + if (__has_val_) { + __reinit_expected(__unex_, __val_, std::move(__un.error())); + __has_val_ = false; + } else { + __unex_ = std::move(__un.error()); + } + return *this; + } + + template + requires is_nothrow_constructible_v<_Tp, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept { + if (__has_val_) { + std::destroy_at(std::addressof(__val_)); + } else { + std::destroy_at(std::addressof(__unex_)); + __has_val_ = true; + } + return *std::construct_at(std::addressof(__val_), std::forward<_Args>(__args)...); + } + + template + requires is_nothrow_constructible_v< _Tp, initializer_list<_Up>&, _Args... > + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept { + if (__has_val_) { + std::destroy_at(std::addressof(__val_)); + } else { + std::destroy_at(std::addressof(__unex_)); + __has_val_ = true; + } + return *std::construct_at(std::addressof(__val_), __il, std::forward<_Args>(__args)...); + } + +private: + _LIBCPP_HIDE_FROM_ABI static constexpr void __swap_val_unex_impl(expected& __with_val, expected& __with_err) // + noexcept(is_nothrow_move_constructible_v<_Tp>&& is_nothrow_move_constructible_v<_Err>) { + if constexpr (is_nothrow_move_constructible_v<_Err>) { + _Err __tmp(std::move(__with_err.__unex_)); + std::destroy_at(std::addressof(__with_err.__unex_)); + __transaction __trans([&] { std::construct_at(std::addressof(__with_err.__unex_), std::move(__tmp)); }); + std::construct_at(std::addressof(__with_err.__val_), std::move(__with_val.__val_)); + __trans.__complete(); + std::destroy_at(std::addressof(__with_val.__val_)); + std::construct_at(std::addressof(__with_val.__unex_), std::move(__tmp)); + } else { + static_assert(is_nothrow_move_constructible_v<_Tp>, + "To provide strong exception guarrentee, Tp has to satisfy `is_nothrow_move_constructible_v` so " + "that it can be reverted to the previous state in case an exception is thrown during swap."); + _Tp __tmp(std::move(__with_val.__val_)); + std::destroy_at(std::addressof(__with_val.__val_)); + __transaction __trans([&] { std::construct_at(std::addressof(__with_val.__val_), std::move(__tmp)); }); + std::construct_at(std::addressof(__with_val.__unex_), std::move(__with_err.__unex_)); + __trans.__complete(); + std::destroy_at(std::addressof(__with_err.__unex_)); + std::construct_at(std::addressof(__with_err.__val_), std::move(__tmp)); + } + __with_val.__has_val_ = false; + __with_err.__has_val_ = true; + } + +public: + // [expected.object.swap], swap + _LIBCPP_HIDE_FROM_ABI constexpr void swap(expected& __rhs) // + noexcept((is_nothrow_move_constructible_v<_Tp> && // + is_nothrow_swappable_v<_Tp> && // + is_nothrow_move_constructible_v<_Err> && // + is_nothrow_swappable_v<_Err>)) + requires(is_swappable_v<_Tp> && // + is_swappable_v<_Err> && // + is_move_constructible_v<_Tp> && // + is_move_constructible_v<_Err> && // + (is_nothrow_move_constructible_v<_Tp> || // + is_nothrow_move_constructible_v<_Err>)) + { + if (__has_val_) { + if (__rhs.__has_val_) { + using std::swap; + swap(__val_, __rhs.__val_); + } else { + __swap_val_unex_impl(*this, __rhs); + } + } else { + if (__rhs.__has_val_) { + __swap_val_unex_impl(__rhs, *this); + } else { + using std::swap; + swap(__unex_, __rhs.__unex_); + } + } + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(expected& __x, expected& __y) // + noexcept(noexcept(__x.swap(__y))) { + __x.swap(__y); + } + + // [expected.object.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept { + _LIBCPP_ASSERT(__has_val_, "expected::operator-> requires the expected to contain a value"); + return std::addressof(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept { + _LIBCPP_ASSERT(__has_val_, "expected::operator-> requires the expected to contain a value"); + return std::addressof(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept { + _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); + return __val_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept { + _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); + return __val_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept { + _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); + return std::move(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept { + _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); + return std::move(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __has_val_; } + + _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_val_; } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& { + if (!__has_val_) { + __expected::__throw_bad_expected_access<_Err>(__unex_); + } + return __val_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & { + if (!__has_val_) { + __expected::__throw_bad_expected_access<_Err>(__unex_); + } + return __val_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& { + if (!__has_val_) { + __expected::__throw_bad_expected_access<_Err>(std::move(__unex_)); + } + return std::move(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && { + if (!__has_val_) { + __expected::__throw_bad_expected_access<_Err>(std::move(__unex_)); + } + return std::move(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { + _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); + return __unex_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { + _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); + return __unex_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { + _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); + return std::move(__unex_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { + _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); + return std::move(__unex_); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& { + static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible"); + static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type"); + return __has_val_ ? __val_ : static_cast<_Tp>(std::forward<_Up>(__v)); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && { + static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type"); + return __has_val_ ? std::move(__val_) : static_cast<_Tp>(std::forward<_Up>(__v)); + } + + // [expected.object.eq], equality operators + template + requires(!is_void_v<_T2>) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { + if (__x.__has_val_ != __y.__has_val_) { + return false; + } else { + if (__x.__has_val_) { + return __x.__val_ == __y.__val_; + } else { + return __x.__unex_ == __y.__unex_; + } + } + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) { + return __x.__has_val_ && static_cast(__x.__val_ == __v); + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) { + return !__x.__has_val_ && static_cast(__x.__unex_ == __e.error()); + } + +private: + union { + _Tp __val_; + _Err __unex_; + }; + bool __has_val_; +}; + +template + requires is_void_v<_Tp> +class expected<_Tp, _Err> { + static_assert(__unexpected::__valid_unexpected<_Err>::value, + "[expected.void.general] A program that instantiates the definition of the template expected " + "with a type for the E parameter that is not a valid template argument for unexpected is ill-formed"); + + template + friend class expected; + + template + using __can_convert = _And< // + is_void<_Up>, // + is_constructible<_Err, _Gf>, // + _Not, expected<_Up, _Gp>&>>, // + _Not, expected<_Up, _Gp>>>, // + _Not, const expected<_Up, _Gp>&>>, // + _Not, const expected<_Up, _Gp>>>>; + + _LIBCPP_HIDE_FROM_ABI static constexpr void __swap_val_unex_impl(expected& __with_val, expected& __with_err) // + noexcept(is_nothrow_move_constructible_v<_Err>) { + std::construct_at(std::addressof(__with_val.__unex_), std::move(__with_err.__unex_)); + std::destroy_at(std::addressof(__with_err.__unex_)); + __with_val.__has_val_ = false; + __with_err.__has_val_ = true; + } + +public: + using value_type = _Tp; + using error_type = _Err; + using unexpected_type = unexpected<_Err>; + + template + using rebind = expected<_Up, error_type>; + + // [expected.void.ctor], constructors + _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __has_val_(true) {} + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) + requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs) // + noexcept(is_nothrow_copy_constructible_v<_Err>) + requires(is_copy_constructible_v<_Err> && !is_trivially_copy_constructible_v<_Err>) + : __has_val_(__rhs.__has_val_) { + if (!__rhs.__has_val_) { + std::construct_at(std::addressof(__unex_), __rhs.__unex_); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&) + requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs) // + noexcept(is_nothrow_move_constructible_v<_Err>) + requires(is_move_constructible_v<_Err> && !is_trivially_move_constructible_v<_Err>) + : __has_val_(__rhs.__has_val_) { + if (!__rhs.__has_val_) { + std::construct_at(std::addressof(__unex_), std::move(__rhs.__unex_)); + } + } + + template + requires __can_convert<_Up, _Gp, const _Gp&>::value + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) // + expected(const expected<_Up, _Gp>& __rhs) // + noexcept(is_nothrow_constructible_v<_Err, const _Gp&>) + : __has_val_(__rhs.__has_val_) { + if (!__rhs.__has_val_) { + std::construct_at(std::addressof(__unex_), __rhs.__unex_); + } + } + + template + requires __can_convert<_Up, _Gp, _Gp>::value + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Gp, _Err>) // + expected(expected<_Up, _Gp>&& __rhs) // + noexcept(is_nothrow_constructible_v<_Err, _Gp>) + : __has_val_(__rhs.__has_val_) { + if (!__rhs.__has_val_) { + std::construct_at(std::addressof(__unex_), std::move(__rhs.__unex_)); + } + } + + template + requires is_constructible_v<_Err, const _Gp&> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) + expected(const unexpected<_Gp>& __unex) // + noexcept(is_nothrow_constructible_v<_Err, const _Gp&>) + : __has_val_(false), __unex_(__unex.error()) {} + + template + requires is_constructible_v<_Err, _Gp> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Gp, _Err>) // + expected(unexpected<_Gp>&& __unex) // + noexcept(is_nothrow_constructible_v<_Err, _Gp>) + : __has_val_(false), __unex_(std::move(__unex.error())) {} + + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __has_val_(true) {} + + template + requires is_constructible_v<_Err, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) // + noexcept(is_nothrow_constructible_v<_Err, _Args...>) + : __has_val_(false), __unex_(std::forward<_Args>(__args)...) {} + + template + requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... > + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) + : __has_val_(false), __unex_(__il, std::forward<_Args>(__args)...) {} + + // [expected.void.dtor], destructor + +# if __cpp_concepts >= 202002 + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() + requires is_trivially_destructible_v<_Err> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() + requires(!is_trivially_destructible_v<_Err>) + { + if (!__has_val_) { + std::destroy_at(std::addressof(__unex_)); + } + } +# else + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() { + if (!__has_val_) { + std::destroy_at(std::addressof(__unex_)); + } + } +# endif + + // [expected.void.assign], assignment + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) // + noexcept((is_nothrow_copy_assignable_v<_Err> && // + is_nothrow_copy_constructible_v<_Err>)) + requires(is_copy_assignable_v<_Err> && // + is_copy_constructible_v<_Err>) + { + if (__has_val_) { + if (!__rhs.__has_val_) { + std::construct_at(std::addressof(__unex_), __rhs.__unex_); + __has_val_ = false; + } + } else { + if (__rhs.__has_val_) { + std::destroy_at(std::addressof(__unex_)); + __has_val_ = true; + } else { + __unex_ = __rhs.__unex_; + } + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs) // + noexcept((is_nothrow_move_assignable_v<_Err> && // + is_nothrow_move_constructible_v<_Err>)) + requires(is_move_assignable_v<_Err> && // + is_move_constructible_v<_Err>) + { + if (__has_val_) { + if (!__rhs.__has_val_) { + std::construct_at(std::addressof(__unex_), std::move(__rhs.__unex_)); + __has_val_ = false; + } + } else { + if (__rhs.__has_val_) { + std::destroy_at(std::addressof(__unex_)); + __has_val_ = true; + } else { + __unex_ = std::move(__rhs.__unex_); + } + } + return *this; + } + + template + requires(is_constructible_v<_Err, const _Gp&> && is_assignable_v<_Err&, const _Gp&>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_Gp>& __un) { + if (__has_val_) { + std::construct_at(std::addressof(__unex_), __un.error()); + __has_val_ = false; + } else { + __unex_ = __un.error(); + } + return *this; + } + + template + requires(is_constructible_v<_Err, _Gp> && is_assignable_v<_Err&, _Gp>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_Gp>&& __un) { + if (__has_val_) { + std::construct_at(std::addressof(__unex_), std::move(__un.error())); + __has_val_ = false; + } else { + __unex_ = std::move(__un.error()); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept { + if (!__has_val_) { + std::destroy_at(std::addressof(__unex_)); + __has_val_ = true; + } + } + + // [expected.void.swap], swap + _LIBCPP_HIDE_FROM_ABI constexpr void swap(expected& __rhs) // + noexcept((is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)) + requires(is_swappable_v<_Err> && is_move_constructible_v<_Err>) + { + if (__has_val_) { + if (!__rhs.__has_val_) { + __swap_val_unex_impl(*this, __rhs); + } + } else { + if (__rhs.__has_val_) { + __swap_val_unex_impl(__rhs, *this); + } else { + using std::swap; + swap(__unex_, __rhs.__unex_); + } + } + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(expected& __x, expected& __y) // + noexcept(noexcept(__x.swap(__y))) { + __x.swap(__y); + } + + // [expected.void.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __has_val_; } + + _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_val_; } + + _LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept { + _LIBCPP_ASSERT(__has_val_, "expected::operator* requires the expected to contain a value"); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void value() const& { + if (!__has_val_) { + __expected::__throw_bad_expected_access<_Err>(__unex_); + } + } + + constexpr void value() && { + if (!__has_val_) { + __expected::__throw_bad_expected_access<_Err>(std::move(__unex_)); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { + _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); + return __unex_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { + _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); + return __unex_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { + _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); + return std::move(__unex_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { + _LIBCPP_ASSERT(!__has_val_, "expected::error requires the expected to contain an error"); + return std::move(__unex_); + } + + // [expected.void.eq], equality operators + template + requires is_void_v<_T2> + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { + if (__x.__has_val_ != __y.__has_val_) { + return false; + } else { + return __x.__has_val_ || static_cast(__x.__unex_ == __y.__unex_); + } + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) { + return !__x.__has_val_ && static_cast(__x.__unex_ == __y.error()); + } + +private: + bool __has_val_; + union { + _Err __unex_; + }; +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP___EXPECTED_EXPECTED_H diff --git a/libcxx/include/__expected/unexpect.h b/libcxx/include/__expected/unexpect.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__expected/unexpect.h @@ -0,0 +1,32 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___EXPECTED_UNEXPECT_H +#define _LIBCPP___EXPECTED_UNEXPECT_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct unexpect_t { + _LIBCPP_HIDE_FROM_ABI explicit unexpect_t() = default; +}; + +inline constexpr unexpect_t unexpect{}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP___EXPECTED_UNEXPECT_H diff --git a/libcxx/include/__expected/unexpected.h b/libcxx/include/__expected/unexpected.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__expected/unexpected.h @@ -0,0 +1,126 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___EXPECTED_UNEXPECTED_H +#define _LIBCPP___EXPECTED_UNEXPECTED_H + +#include <__config> +#include <__type_traits/conjunction.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_const.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_swappable.h> +#include <__type_traits/is_volatile.h> +#include <__type_traits/negation.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/swap.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class unexpected; + +namespace __unexpected { + +template +struct __is_unexpected : false_type {}; + +template +struct __is_unexpected> : true_type {}; + +template +using __valid_unexpected = _BoolConstant< // + is_object_v<_Tp> && // + !is_array_v<_Tp> && // + !__is_unexpected<_Tp>::value && // + !is_const_v<_Tp> && // + !is_volatile_v<_Tp> // + >; + +} // namespace __unexpected + +template +class unexpected { + static_assert(__unexpected::__valid_unexpected<_Err>::value, + "[expected.un.general] states a program that instantiates std::unexpected for a non-object type, an " + "array type, a specialization of unexpected, or a cv-qualified type is ill-formed."); + +public: + _LIBCPP_HIDE_FROM_ABI constexpr unexpected(const unexpected&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr unexpected(unexpected&&) = default; + + template + requires(!is_same_v, unexpected> && // + !is_same_v, in_place_t> && // + is_constructible_v<_Err, _Error>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(_Error&& __error) // + noexcept(is_nothrow_constructible_v<_Err, _Error>) + : __unex_(std::forward<_Error>(__error)) {} + + template + requires is_constructible_v<_Err, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(in_place_t, _Args&&... __args) // + noexcept(is_nothrow_constructible_v<_Err, _Args...>) + : __unex_(std::forward<_Args>(__args)...) {} + + template + requires is_constructible_v<_Err, initializer_list<_Up>&, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) // + noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) + : __unex_(__il, std::forward<_Args>(__args)...) {} + + _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(const unexpected&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(unexpected&&) = default; + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { return __unex_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { return __unex_; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { return std::move(__unex_); } + _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { return std::move(__unex_); } + + _LIBCPP_HIDE_FROM_ABI constexpr void swap(unexpected& __other) noexcept(is_nothrow_swappable_v<_Err>) { + static_assert(is_swappable_v<_Err>, "unexpected::swap requires is_swappable_v to be true"); + using std::swap; + swap(__unex_, __other.__unex_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(unexpected& __x, unexpected& __y) noexcept(noexcept(__x.swap(__y))) + requires is_swappable_v<_Err> + { + __x.swap(__y); + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const unexpected& __x, const unexpected<_Err2>& __y) { + return __x.__unex_ == __y.__unex_; + } + +private: + _Err __unex_; +}; + +template +unexpected(_Err) -> unexpected<_Err>; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP___EXPECTED_UNEXPECTED_H diff --git a/libcxx/include/__type_traits/is_member_pointer.h b/libcxx/include/__type_traits/is_member_pointer.h --- a/libcxx/include/__type_traits/is_member_pointer.h +++ b/libcxx/include/__type_traits/is_member_pointer.h @@ -12,6 +12,10 @@ #include <__config> #include <__type_traits/integral_constant.h> +#if !__has_builtin(__is_member_pointer) +#include <__type_traits/is_member_function_pointer.h> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif diff --git a/libcxx/include/__type_traits/is_nothrow_constructible.h b/libcxx/include/__type_traits/is_nothrow_constructible.h --- a/libcxx/include/__type_traits/is_nothrow_constructible.h +++ b/libcxx/include/__type_traits/is_nothrow_constructible.h @@ -12,6 +12,11 @@ #include <__config> #include <__type_traits/integral_constant.h> +#if !__has_builtin(__is_nothrow_constructible) +#include <__type_traits/is_reference.h> +#include <__utility/declval.h> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif diff --git a/libcxx/include/__type_traits/is_scalar.h b/libcxx/include/__type_traits/is_scalar.h --- a/libcxx/include/__type_traits/is_scalar.h +++ b/libcxx/include/__type_traits/is_scalar.h @@ -14,6 +14,7 @@ #include <__type_traits/is_arithmetic.h> #include <__type_traits/is_enum.h> #include <__type_traits/is_member_pointer.h> +#include <__type_traits/is_null_pointer.h> #include <__type_traits/is_pointer.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/libcxx/include/__type_traits/is_void.h b/libcxx/include/__type_traits/is_void.h --- a/libcxx/include/__type_traits/is_void.h +++ b/libcxx/include/__type_traits/is_void.h @@ -12,6 +12,11 @@ #include <__config> #include <__type_traits/integral_constant.h> +#if !__has_builtin(__is_void) +#include <__type_traits/is_same.h> +#include <__type_traits/remove_cv.h> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif diff --git a/libcxx/include/expected b/libcxx/include/expected new file mode 100644 --- /dev/null +++ b/libcxx/include/expected @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_EXEPECTED +#define _LIBCPP_EXEPECTED + +/* + Header synopsis + +namespace std { + // [expected.unexpected], class template unexpected + template class unexpected; + + // [expected.bad], class template bad_expected_access + template class bad_expected_access; + + // [expected.bad.void], specialization for void + template<> class bad_expected_access; + + // in-place construction of unexpected values + struct unexpect_t { + explicit unexpect_t() = default; + }; + inline constexpr unexpect_t unexpect{}; + + // [expected.expected], class template expected + template class expected; + + // [expected.void], partial specialization of expected for void types + template requires is_void_v class expected; +} + +*/ + +#include <__assert> // all public C++ headers provide the assertion handler +#include <__config> +#include <__expected/bad_expected_access.h> +#include <__expected/expected.h> +#include <__expected/unexpect.h> +#include <__expected/unexpected.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#endif // _LIBCPP_EXEPECTED + diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -784,6 +784,17 @@ header "execution" export * } + module expected { + header "expected" + export * + + module __expected { + module bad_expected_access { private header "__expected/bad_expected_access.h" } + module expected { private header "__expected/expected.h" } + module unexpect { private header "__expected/unexpect.h" } + module unexpected { private header "__expected/unexpected.h" } + } + } module filesystem { @requires_LIBCXX_ENABLE_FILESYSTEM@ header "filesystem" diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -82,6 +82,7 @@ __cpp_lib_exchange_function 201304L __cpp_lib_execution 201902L 201603L // C++17 +__cpp_lib_expected 202202L __cpp_lib_filesystem 201703L __cpp_lib_format 202106L __cpp_lib_forward_like 202207L @@ -390,6 +391,7 @@ # undef __cpp_lib_constexpr_memory # define __cpp_lib_constexpr_memory 202202L // # define __cpp_lib_constexpr_typeinfo 202106L +# define __cpp_lib_expected 202202L # define __cpp_lib_forward_like 202207L // # define __cpp_lib_invoke_r 202106L # define __cpp_lib_is_scoped_enum 202011L diff --git a/libcxx/test/libcxx/clang_tidy.sh.cpp b/libcxx/test/libcxx/clang_tidy.sh.cpp --- a/libcxx/test/libcxx/clang_tidy.sh.cpp +++ b/libcxx/test/libcxx/clang_tidy.sh.cpp @@ -91,6 +91,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) # include diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp --- a/libcxx/test/libcxx/double_include.sh.cpp +++ b/libcxx/test/libcxx/double_include.sh.cpp @@ -93,6 +93,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) # include diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp --- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp @@ -139,6 +139,8 @@ TEST_MACROS(); #include TEST_MACROS(); +#include +TEST_MACROS(); #include TEST_MACROS(); #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) diff --git a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp --- a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp @@ -212,6 +212,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) # include diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp --- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp +++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp @@ -90,6 +90,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) # include diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -301,6 +301,10 @@ #include <__coroutine/trivial_awaitables.h> // expected-error@*:* {{use of private header from outside its module: '__coroutine/trivial_awaitables.h'}} #include <__debug_utils/randomize_range.h> // expected-error@*:* {{use of private header from outside its module: '__debug_utils/randomize_range.h'}} #include <__errc> // expected-error@*:* {{use of private header from outside its module: '__errc'}} +#include <__expected/bad_expected_access.h> // expected-error@*:* {{use of private header from outside its module: '__expected/bad_expected_access.h'}} +#include <__expected/expected.h> // expected-error@*:* {{use of private header from outside its module: '__expected/expected.h'}} +#include <__expected/unexpect.h> // expected-error@*:* {{use of private header from outside its module: '__expected/unexpect.h'}} +#include <__expected/unexpected.h> // expected-error@*:* {{use of private header from outside its module: '__expected/unexpected.h'}} #include <__filesystem/copy_options.h> // expected-error@*:* {{use of private header from outside its module: '__filesystem/copy_options.h'}} #include <__filesystem/directory_entry.h> // expected-error@*:* {{use of private header from outside its module: '__filesystem/directory_entry.h'}} #include <__filesystem/directory_iterator.h> // expected-error@*:* {{use of private header from outside its module: '__filesystem/directory_iterator.h'}} diff --git a/libcxx/test/libcxx/transitive_includes.sh.cpp b/libcxx/test/libcxx/transitive_includes.sh.cpp --- a/libcxx/test/libcxx/transitive_includes.sh.cpp +++ b/libcxx/test/libcxx/transitive_includes.sh.cpp @@ -252,311 +252,388 @@ #if defined(TEST_45) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_47 2> %t/header.filesystem -#if defined(TEST_47) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_46 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.expected +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.expected %t.actual.expected +#if defined(TEST_46) +#include +#endif +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_48 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.filesystem +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.filesystem %t.actual.filesystem +#if defined(TEST_48) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_49 2> %t/header.format -#if defined(TEST_49) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_50 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.format +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.format %t.actual.format +#if defined(TEST_50) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_50 2> %t/header.forward_list -#if defined(TEST_50) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_51 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.forward_list +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.forward_list %t.actual.forward_list +#if defined(TEST_51) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_51 2> %t/header.fstream -#if defined(TEST_51) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_52 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.fstream +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.fstream %t.actual.fstream +#if defined(TEST_52) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_52 2> %t/header.functional -#if defined(TEST_52) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_53 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.functional +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.functional %t.actual.functional +#if defined(TEST_53) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_53 2> %t/header.future -#if defined(TEST_53) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_54 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.future +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.future %t.actual.future +#if defined(TEST_54) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_54 2> %t/header.initializer_list -#if defined(TEST_54) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_55 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.initializer_list +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.initializer_list %t.actual.initializer_list +#if defined(TEST_55) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_56 2> %t/header.iomanip -#if defined(TEST_56) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_57 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.iomanip +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.iomanip %t.actual.iomanip +#if defined(TEST_57) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_57 2> %t/header.ios -#if defined(TEST_57) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_58 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.ios +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.ios %t.actual.ios +#if defined(TEST_58) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_58 2> %t/header.iosfwd -#if defined(TEST_58) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_59 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.iosfwd +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.iosfwd %t.actual.iosfwd +#if defined(TEST_59) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_59 2> %t/header.iostream -#if defined(TEST_59) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_60 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.iostream +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.iostream %t.actual.iostream +#if defined(TEST_60) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_60 2> %t/header.istream -#if defined(TEST_60) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_61 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.istream +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.istream %t.actual.istream +#if defined(TEST_61) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_61 2> %t/header.iterator -#if defined(TEST_61) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_62 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.iterator +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.iterator %t.actual.iterator +#if defined(TEST_62) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_62 2> %t/header.latch -#if defined(TEST_62) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_63 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.latch +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.latch %t.actual.latch +#if defined(TEST_63) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_63 2> %t/header.limits -#if defined(TEST_63) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_64 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.limits +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.limits %t.actual.limits +#if defined(TEST_64) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_65 2> %t/header.list -#if defined(TEST_65) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_66 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.list +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.list %t.actual.list +#if defined(TEST_66) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_66 2> %t/header.locale -#if defined(TEST_66) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_67 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.locale +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.locale %t.actual.locale +#if defined(TEST_67) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_68 2> %t/header.map -#if defined(TEST_68) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_69 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.map +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.map %t.actual.map +#if defined(TEST_69) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_70 2> %t/header.memory -#if defined(TEST_70) -#include -#endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_71 2> %t/header.memory_resource +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_71 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.memory +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.memory %t.actual.memory #if defined(TEST_71) -#include +#include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_72 2> %t/header.mutex +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_72 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.mutex +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.mutex %t.actual.mutex #if defined(TEST_72) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_73 2> %t/header.new +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_73 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.new +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.new %t.actual.new #if defined(TEST_73) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_74 2> %t/header.numbers +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_74 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.numbers +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.numbers %t.actual.numbers #if defined(TEST_74) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_75 2> %t/header.numeric +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_75 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.numeric +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.numeric %t.actual.numeric #if defined(TEST_75) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_76 2> %t/header.optional +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_76 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.optional +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.optional %t.actual.optional #if defined(TEST_76) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_77 2> %t/header.ostream +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_77 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.ostream +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.ostream %t.actual.ostream #if defined(TEST_77) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_78 2> %t/header.queue +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_78 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.queue +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.queue %t.actual.queue #if defined(TEST_78) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_79 2> %t/header.random +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_79 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.random +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.random %t.actual.random #if defined(TEST_79) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_80 2> %t/header.ranges +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_80 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.ranges +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.ranges %t.actual.ranges #if defined(TEST_80) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_81 2> %t/header.ratio +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_81 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.ratio +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.ratio %t.actual.ratio #if defined(TEST_81) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_82 2> %t/header.regex +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_82 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.regex +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.regex %t.actual.regex #if defined(TEST_82) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_83 2> %t/header.scoped_allocator +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_83 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.scoped_allocator +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.scoped_allocator %t.actual.scoped_allocator #if defined(TEST_83) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_84 2> %t/header.semaphore +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_84 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.semaphore +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.semaphore %t.actual.semaphore #if defined(TEST_84) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_85 2> %t/header.set +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_85 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.set +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.set %t.actual.set #if defined(TEST_85) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_87 2> %t/header.shared_mutex +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_87 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.shared_mutex +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.shared_mutex %t.actual.shared_mutex #if defined(TEST_87) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_88 2> %t/header.span +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_88 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.span +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.span %t.actual.span #if defined(TEST_88) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_89 2> %t/header.sstream +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_89 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.sstream +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.sstream %t.actual.sstream #if defined(TEST_89) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_90 2> %t/header.stack +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_90 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.stack +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.stack %t.actual.stack #if defined(TEST_90) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_94 2> %t/header.stdexcept +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_94 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.stdexcept +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.stdexcept %t.actual.stdexcept #if defined(TEST_94) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_98 2> %t/header.streambuf +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_98 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.streambuf +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.streambuf %t.actual.streambuf #if defined(TEST_98) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_99 2> %t/header.string +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_99 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.string +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.string %t.actual.string #if defined(TEST_99) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_101 2> %t/header.string_view +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_101 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.string_view +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.string_view %t.actual.string_view #if defined(TEST_101) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_102 2> %t/header.strstream +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_102 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.strstream +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.strstream %t.actual.strstream #if defined(TEST_102) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_103 2> %t/header.system_error +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_103 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.system_error +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.system_error %t.actual.system_error #if defined(TEST_103) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_105 2> %t/header.thread +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_105 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.thread +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.thread %t.actual.thread #if defined(TEST_105) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_106 2> %t/header.tuple +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_106 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.tuple +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.tuple %t.actual.tuple #if defined(TEST_106) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_107 2> %t/header.type_traits +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_107 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.type_traits +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.type_traits %t.actual.type_traits #if defined(TEST_107) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_108 2> %t/header.typeindex +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_108 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.typeindex +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.typeindex %t.actual.typeindex #if defined(TEST_108) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_109 2> %t/header.typeinfo +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_109 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.typeinfo +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.typeinfo %t.actual.typeinfo #if defined(TEST_109) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_111 2> %t/header.unordered_map +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_111 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.unordered_map +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.unordered_map %t.actual.unordered_map #if defined(TEST_111) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_112 2> %t/header.unordered_set +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_112 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.unordered_set +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.unordered_set %t.actual.unordered_set #if defined(TEST_112) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_113 2> %t/header.utility +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_113 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.utility +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.utility %t.actual.utility #if defined(TEST_113) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_114 2> %t/header.valarray +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_114 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.valarray +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.valarray %t.actual.valarray #if defined(TEST_114) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_115 2> %t/header.variant +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_115 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.variant +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.variant %t.actual.variant #if defined(TEST_115) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_116 2> %t/header.vector +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_116 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.vector +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.vector %t.actual.vector #if defined(TEST_116) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_117 2> %t/header.version +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_117 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.version +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.version %t.actual.version #if defined(TEST_117) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_120 2> %t/header.experimental_algorithm +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_120 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_algorithm +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_algorithm %t.actual.experimental_algorithm #if defined(TEST_120) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_121 2> %t/header.experimental_coroutine +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_121 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_coroutine +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_coroutine %t.actual.experimental_coroutine #if defined(TEST_121) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_122 2> %t/header.experimental_deque +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_122 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_deque +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_deque %t.actual.experimental_deque #if defined(TEST_122) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_123 2> %t/header.experimental_forward_list +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_123 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_forward_list +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_forward_list %t.actual.experimental_forward_list #if defined(TEST_123) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_124 2> %t/header.experimental_functional +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_124 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_functional +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_functional %t.actual.experimental_functional #if defined(TEST_124) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_125 2> %t/header.experimental_iterator +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_125 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_iterator +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_iterator %t.actual.experimental_iterator #if defined(TEST_125) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_126 2> %t/header.experimental_list +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_126 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_list +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_list %t.actual.experimental_list #if defined(TEST_126) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_127 2> %t/header.experimental_map +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_127 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_map +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_map %t.actual.experimental_map #if defined(TEST_127) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_128 2> %t/header.experimental_memory_resource +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_128 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_memory_resource +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_memory_resource %t.actual.experimental_memory_resource #if defined(TEST_128) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_129 2> %t/header.experimental_propagate_const +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_129 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_propagate_const +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_propagate_const %t.actual.experimental_propagate_const #if defined(TEST_129) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_130 2> %t/header.experimental_regex +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_130 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_regex +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_regex %t.actual.experimental_regex #if defined(TEST_130) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_131 2> %t/header.experimental_set +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_131 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_set +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_set %t.actual.experimental_set #if defined(TEST_131) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_132 2> %t/header.experimental_simd +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_132 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_simd +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_simd %t.actual.experimental_simd #if defined(TEST_132) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_133 2> %t/header.experimental_string +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_133 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_string +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_string %t.actual.experimental_string #if defined(TEST_133) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_134 2> %t/header.experimental_type_traits +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_134 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_type_traits +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_type_traits %t.actual.experimental_type_traits #if defined(TEST_134) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_135 2> %t/header.experimental_unordered_map +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_135 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_unordered_map +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_unordered_map %t.actual.experimental_unordered_map #if defined(TEST_135) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_136 2> %t/header.experimental_unordered_set +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_136 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_unordered_set +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_unordered_set %t.actual.experimental_unordered_set #if defined(TEST_136) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_137 2> %t/header.experimental_utility +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_137 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_utility +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_utility %t.actual.experimental_utility #if defined(TEST_137) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_138 2> %t/header.experimental_vector +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_138 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.experimental_vector +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.experimental_vector %t.actual.experimental_vector #if defined(TEST_138) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_139 2> %t/header.ext_hash_map +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_139 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.ext_hash_map +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.ext_hash_map %t.actual.ext_hash_map #if defined(TEST_139) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_140 2> %t/header.ext_hash_set +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fsyntax-only -DTEST_140 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t.actual.ext_hash_set +// RUN: diff -w %S/transitive_includes/%{cxx_std}/expected.ext_hash_set %t.actual.ext_hash_set #if defined(TEST_140) #include #endif diff --git a/libcxx/test/libcxx/transitive_includes/cxx03/expected.expected b/libcxx/test/libcxx/transitive_includes/cxx03/expected.expected new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/transitive_includes/cxx03/expected.expected @@ -0,0 +1,8 @@ +cstddef +cstdint +cstdlib +exception +initializer_list +new +type_traits +version diff --git a/libcxx/test/libcxx/transitive_includes/cxx11/expected.expected b/libcxx/test/libcxx/transitive_includes/cxx11/expected.expected new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/transitive_includes/cxx11/expected.expected @@ -0,0 +1,8 @@ +cstddef +cstdint +cstdlib +exception +initializer_list +new +type_traits +version diff --git a/libcxx/test/libcxx/transitive_includes/cxx14/expected.expected b/libcxx/test/libcxx/transitive_includes/cxx14/expected.expected new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/transitive_includes/cxx14/expected.expected @@ -0,0 +1,8 @@ +cstddef +cstdint +cstdlib +exception +initializer_list +new +type_traits +version diff --git a/libcxx/test/libcxx/transitive_includes/cxx17/expected.expected b/libcxx/test/libcxx/transitive_includes/cxx17/expected.expected new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/transitive_includes/cxx17/expected.expected @@ -0,0 +1,8 @@ +cstddef +cstdint +cstdlib +exception +initializer_list +new +type_traits +version diff --git a/libcxx/test/libcxx/transitive_includes/cxx20/expected.expected b/libcxx/test/libcxx/transitive_includes/cxx20/expected.expected new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/transitive_includes/cxx20/expected.expected @@ -0,0 +1,8 @@ +cstddef +cstdint +cstdlib +exception +initializer_list +new +type_traits +version diff --git a/libcxx/test/libcxx/transitive_includes/cxx2b/expected.expected b/libcxx/test/libcxx/transitive_includes/cxx2b/expected.expected new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/transitive_includes/cxx2b/expected.expected @@ -0,0 +1,8 @@ +cstddef +cstdint +cstdlib +exception +initializer_list +new +type_traits +version diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.arrow.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.arrow.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.arrow.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// constexpr const T* operator->() const noexcept; +// constexpr T* operator->() noexcept; +// +// Preconditions: has_value() is true. + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + std::expected e{std::unexpect, 5}; + TEST_LIBCPP_ASSERT_FAILURE(e.operator->(), "expected::operator-> requires the expected to contain a value"); + TEST_LIBCPP_ASSERT_FAILURE(std::as_const(e).operator->(), "expected::operator-> requires the expected to contain a value"); + + return 0; +} diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.deref.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.deref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.deref.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// constexpr const T& operator*() const & noexcept; +// constexpr T& operator*() & noexcept; +// constexpr T&& operator*() && noexcept; +// constexpr const T&& operator*() const && noexcept; +// +// Preconditions: has_value() is true. + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + std::expected e{std::unexpect, 5}; + TEST_LIBCPP_ASSERT_FAILURE(*e, "expected::operator* requires the expected to contain a value"); + TEST_LIBCPP_ASSERT_FAILURE(*std::as_const(e), "expected::operator* requires the expected to contain a value"); + TEST_LIBCPP_ASSERT_FAILURE(*std::move(e), "expected::operator* requires the expected to contain a value"); + TEST_LIBCPP_ASSERT_FAILURE(*std::move(std::as_const(e)), "expected::operator* requires the expected to contain a value"); + + return 0; +} diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/assert.error.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/assert.error.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// constexpr const E& error() const & noexcept; +// constexpr E& error() & noexcept; +// constexpr E&& error() && noexcept; +// constexpr const E&& error() const && noexcept; +// +// Preconditions: has_value() is false. + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + std::expected e{std::in_place, 5}; + TEST_LIBCPP_ASSERT_FAILURE(e.error(), "expected::error requires the expected to contain an error"); + TEST_LIBCPP_ASSERT_FAILURE(std::as_const(e).error(), "expected::error requires the expected to contain an error"); + TEST_LIBCPP_ASSERT_FAILURE(std::move(e).error(), "expected::error requires the expected to contain an error"); + TEST_LIBCPP_ASSERT_FAILURE(std::move(std::as_const(e)).error(), "expected::error requires the expected to contain an error"); + + return 0; +} diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/value_or.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/value_or.mandates.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/value_or.mandates.verify.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// Test the mandates +// template constexpr T value_or(U&& v) const &; +// Mandates: is_copy_constructible_v is true and is_convertible_v is true. + +// template constexpr T value_or(U&& v) &&; +// Mandates: is_move_constructible_v is true and is_convertible_v is true. + +#include +#include + +struct NonCopyable { + NonCopyable(int) {} + NonCopyable(const NonCopyable&) = delete; +}; + +struct NonMovable { + NonMovable(int) {} + NonMovable(NonMovable&&) = delete; +}; + +struct NotConvertibleFromInt {}; + +void test() { + // const & overload + // !is_copy_constructible_v, + { + const std::expected f1{5}; + f1.value_or(5); + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}value_type has to be copy constructible}} + //expected-error-re@*:* {{{{call to deleted constructor of 'const NonCopyable'}}}} + } + + // const & overload + // !is_convertible_v + { + const std::expected f1{std::in_place}; + f1.value_or(5); + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to value_type}} + //expected-error-re@*:* {{{{no matching conversion for static_cast from 'int' to 'NotConvertibleFromInt'}}}} + } + + // && overload + // !is_move_constructible_v, + { + std::expected f1{5}; + std::move(f1).value_or(5); + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}value_type has to be move constructible}} + //expected-error-re@*:* {{{{call to deleted constructor of}} {{.*}}}} + } + + // && overload + // !is_convertible_v + { + std::expected f1{std::in_place}; + std::move(f1).value_or(5); + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to value_type}} + //expected-error-re@*:* {{{{no matching conversion for static_cast from 'int' to 'NotConvertibleFromInt'}}}} + } +} diff --git a/libcxx/test/libcxx/utilities/expected/expected.unexpected/swap.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.unexpected/swap.mandates.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.unexpected/swap.mandates.verify.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// Test the mandates +// constexpr void swap(unexpected& other) noexcept(is_nothrow_swappable_v); +// Mandates: is_swappable_v is true. + +#include + +struct Foo {}; + +void swap(Foo&, Foo&) = delete; + +void test() { + std::unexpected f1{Foo{}}; + f1.swap(f1); + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}unexpected::swap requires is_swappable_v to be true}} + //expected-error-re@*:* {{{{call to deleted function 'swap'}}}} +} diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/assert.deref.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/assert.deref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.void/assert.deref.pass.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// constexpr void operator*() const noexcept; +// +// Preconditions: has_value() is true. + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + std::expected e{std::unexpect, 5}; + TEST_LIBCPP_ASSERT_FAILURE(*e, "expected::operator* requires the expected to contain a value"); + + return 0; +} diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/assert.error.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/assert.error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.void/assert.error.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +// constexpr const E& error() const & noexcept; +// constexpr E& error() & noexcept; +// constexpr E&& error() && noexcept; +// constexpr const E&& error() const && noexcept; +// +// Preconditions: has_value() is false. + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + std::expected e{std::in_place}; + TEST_LIBCPP_ASSERT_FAILURE(e.error(), "expected::error requires the expected to contain an error"); + TEST_LIBCPP_ASSERT_FAILURE(std::as_const(e).error(), "expected::error requires the expected to contain an error"); + TEST_LIBCPP_ASSERT_FAILURE(std::move(e).error(), "expected::error requires the expected to contain an error"); + TEST_LIBCPP_ASSERT_FAILURE(std::move(std::as_const(e)).error(), "expected::error requires the expected to contain an error"); + + return 0; +} diff --git a/libcxx/test/libcxx/utilities/expected/version.pass.cpp b/libcxx/test/libcxx/utilities/expected/version.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/version.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include + +#include "test_macros.h" + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main(int, char**) +{ + + return 0; +} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_expected 202202L [C++2b] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + +#elif TEST_STD_VER > 20 + +# ifndef __cpp_lib_expected +# error "__cpp_lib_expected should be defined in c++2b" +# endif +# if __cpp_lib_expected != 202202L +# error "__cpp_lib_expected should have the value 202202L in c++2b" +# endif + +#endif // TEST_STD_VER > 20 + diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -76,6 +76,7 @@ __cpp_lib_exchange_function 201304L [C++14] __cpp_lib_execution 201603L [C++17] 201902L [C++20] + __cpp_lib_expected 202202L [C++2b] __cpp_lib_filesystem 201703L [C++17] __cpp_lib_format 202106L [C++20] __cpp_lib_forward_like 202207L [C++2b] @@ -416,6 +417,10 @@ # error "__cpp_lib_execution should not be defined before c++17" # endif +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + # ifdef __cpp_lib_filesystem # error "__cpp_lib_filesystem should not be defined before c++17" # endif @@ -1059,6 +1064,10 @@ # error "__cpp_lib_execution should not be defined before c++17" # endif +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + # ifdef __cpp_lib_filesystem # error "__cpp_lib_filesystem should not be defined before c++17" # endif @@ -1807,6 +1816,10 @@ # endif # endif +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + # if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem) # ifndef __cpp_lib_filesystem # error "__cpp_lib_filesystem should be defined in c++17" @@ -2840,6 +2853,10 @@ # endif # endif +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + # if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem) # ifndef __cpp_lib_filesystem # error "__cpp_lib_filesystem should be defined in c++20" @@ -4077,6 +4094,13 @@ # endif # endif +# ifndef __cpp_lib_expected +# error "__cpp_lib_expected should be defined in c++2b" +# endif +# if __cpp_lib_expected != 202202L +# error "__cpp_lib_expected should have the value 202202L in c++2b" +# endif + # if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem) # ifndef __cpp_lib_filesystem # error "__cpp_lib_filesystem should be defined in c++2b" diff --git a/libcxx/test/std/utilities/expected/expected.bad/ctor.error.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/ctor.error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.bad/ctor.error.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// explicit bad_expected_access(E e); + +// Effects: Initializes unex with std::move(e). + +#include +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" + +// test explicit +static_assert(std::convertible_to); +static_assert(!std::convertible_to>); + +int main(int, char**) { + std::bad_expected_access b(MoveOnly{3}); + assert(b.error().get() == 3); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.bad/error.member.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/error.member.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.bad/error.member.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// E& error() & noexcept; +// const E& error() const & noexcept; +// E&& error() && noexcept; +// const E&& error() const && noexcept; + +#include +#include +#include +#include + +template +concept ErrorNoexcept = + requires(T&& t) { + { std::forward(t).error() } noexcept; + }; + +static_assert(!ErrorNoexcept); +static_assert(ErrorNoexcept&>); +static_assert(ErrorNoexcept const&>); +static_assert(ErrorNoexcept&&>); +static_assert(ErrorNoexcept const&&>); + +void test() { + // & + { + std::bad_expected_access e(5); + decltype(auto) i = e.error(); + static_assert(std::same_as); + assert(i == 5); + } + + // const & + { + const std::bad_expected_access e(5); + decltype(auto) i = e.error(); + static_assert(std::same_as); + assert(i == 5); + } + + // && + { + std::bad_expected_access e(5); + decltype(auto) i = std::move(e).error(); + static_assert(std::same_as); + assert(i == 5); + } + + // const && + { + const std::bad_expected_access e(5); + decltype(auto) i = std::move(e).error(); + static_assert(std::same_as); + assert(i == 5); + } +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.bad/what.noexcept.compile.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/what.noexcept.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.bad/what.noexcept.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// const char* what() const noexcept override; + +#include +#include + +template +concept WhatNoexcept = + requires(const T& t) { + { t.what() } noexcept; + }; + +struct foo{}; + +static_assert(!WhatNoexcept); +static_assert(WhatNoexcept>); +static_assert(WhatNoexcept>); diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp @@ -0,0 +1,346 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr expected& operator=(U&& v); +// +// Constraints: +// - is_same_v> is false; and +// - remove_cvref_t is not a specialization of unexpected; and +// - is_constructible_v is true; and +// - is_assignable_v is true; and +// - is_nothrow_constructible_v || is_nothrow_move_constructible_v || +// is_nothrow_move_constructible_v is true. +// +// Effects: +// - If has_value() is true, equivalent to: val = std::forward(v); +// - Otherwise, equivalent to: +// reinit-expected(val, unex, std::forward(v)); +// has_val = true; +// - Returns: *this. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotCopyConstructible { + NotCopyConstructible(const NotCopyConstructible&) = delete; + NotCopyConstructible& operator=(const NotCopyConstructible&) = default; +}; + +struct NotCopyAssignable { + NotCopyAssignable(const NotCopyAssignable&) = default; + NotCopyAssignable& operator=(const NotCopyAssignable&) = delete; +}; + +// Test constraints +static_assert(std::is_assignable_v&, int>); + +// is_same_v> +// it is true because it covered by the copy assignment +static_assert(std::is_assignable_v&, std::expected>); + +// remove_cvref_t is a specialization of unexpected +// it is true because it covered the unepxected overload +static_assert(std::is_assignable_v&, std::unexpected>); + +// !is_constructible_v +struct NoCtorFromInt { + NoCtorFromInt(int) = delete; + NoCtorFromInt& operator=(int); +}; +static_assert(!std::is_assignable_v&, int>); + +// !is_assignable_v +struct NoAssignFromInt { + explicit NoAssignFromInt(int); + NoAssignFromInt& operator=(int) = delete; +}; +static_assert(!std::is_assignable_v&, int>); + +template +struct MaybeNoexcept { + explicit MaybeNoexcept(int) noexcept(convertNoexcept); + MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept); + MaybeNoexcept& operator=(MaybeNoexcept&&) = default; + MaybeNoexcept& operator=(int); +}; + +// !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, int>&, int>); + +// is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, int>); + +// !is_nothrow_constructible_v && is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, int>); + +// !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(!std::is_assignable_v, MaybeNoexcept>&, int>); + +constexpr bool test() { + // If has_value() is true, equivalent to: val = std::forward(v); + // Copy + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::in_place, oldState, 5); + Traced u(newState, 10); + decltype(auto) x = (e1 = u); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + assert(oldState.copyAssignCalled); + } + + // If has_value() is true, equivalent to: val = std::forward(v); + // Move + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::in_place, oldState, 5); + Traced u(newState, 10); + decltype(auto) x = (e1 = std::move(u)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + assert(oldState.moveAssignCalled); + } + + // Otherwise, equivalent to: + // reinit-expected(val, unex, std::forward(v)); + // is_nothrow_constructible_v && !is_nothrow_move_constructible_v && + // !is_nothrow_move_constructible_v + // copy + // + // In this case, it should call the branch + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + { + BothMayThrow::state oldState{}; + std::expected e1(std::unexpect, oldState, 5); + const int i = 10; + decltype(auto) x = (e1 = i); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.copyCtorCalled); + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e1.value().copiedFromInt); + } + + // Otherwise, equivalent to: + // reinit-expected(val, unex, std::forward(v)); + // is_nothrow_constructible_v && !is_nothrow_move_constructible_v && + // !is_nothrow_move_constructible_v + // move + // + // In this case, it should call the branch + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + { + BothMayThrow::state oldState{}; + std::expected e1(std::unexpect, oldState, 5); + decltype(auto) x = (e1 = 10); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.copyCtorCalled); + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e1.value().movedFromInt); + } + + // Otherwise, equivalent to: + // reinit-expected(val, unex, std::forward(v)); + // !is_nothrow_constructible_v && is_nothrow_move_constructible_v && + // !is_nothrow_move_constructible_v + // copy + // + // In this case, it should call the branch + // T tmp(std::forward(args)...); + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::move(tmp)); + { + BothMayThrow::state oldState{}; + std::expected e1(std::unexpect, oldState, 5); + const int i = 10; + decltype(auto) x = (e1 = i); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.copyCtorCalled); + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!e1.value().copiedFromInt); + assert(e1.value().movedFromTmp); + } + + // Otherwise, equivalent to: + // reinit-expected(val, unex, std::forward(v)); + // !is_nothrow_constructible_v && is_nothrow_move_constructible_v && + // !is_nothrow_move_constructible_v + // move + // + // In this case, it should call the branch + // T tmp(std::forward(args)...); + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::move(tmp)); + { + BothMayThrow::state oldState{}; + std::expected e1(std::unexpect, oldState, 5); + decltype(auto) x = (e1 = 10); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.copyCtorCalled); + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!e1.value().copiedFromInt); + assert(e1.value().movedFromTmp); + } + + // Otherwise, equivalent to: + // reinit-expected(val, unex, std::forward(v)); + // !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && + // is_nothrow_move_constructible_v + // copy + // + // In this case, it should call the branch + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + { + TracedNoexcept::state oldState{}; + std::expected e1(std::unexpect, oldState, 5); + const int i = 10; + decltype(auto) x = (e1 = i); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.copyCtorCalled); + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e1.value().copiedFromInt); + } + + // Otherwise, equivalent to: + // reinit-expected(val, unex, std::forward(v)); + // !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && + // is_nothrow_move_constructible_v + // move + // + // In this case, it should call the branch + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + { + TracedNoexcept::state oldState{}; + std::expected e1(std::unexpect, oldState, 5); + decltype(auto) x = (e1 = 10); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.copyCtorCalled); + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e1.value().movedFromInt); + } + + // Test default template argument. + // Without it, the template parameter cannot be deduced from an initializer list + { + struct Bar { + int i; + int j; + constexpr Bar(int ii, int jj) : i(ii), j(jj) {} + }; + + std::expected e({5, 6}); + e = {7, 8}; + assert(e.value().i == 7); + assert(e.value().j == 8); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowOnConvert { + ThrowOnConvert() = default; + ThrowOnConvert(int) { throw Except{}; } + ThrowOnConvert(const ThrowOnConvert&) noexcept(false) {} + ThrowOnConvert& operator=(const ThrowOnConvert&) = default; + ThrowOnConvert(ThrowOnConvert&&) noexcept(false) {} + ThrowOnConvert& operator=(ThrowOnConvert&&) = default; + }; + + std::expected e1(std::unexpect, 5); + try { + e1 = 10; + assert(false); + } catch (Except) { + assert(!e1.has_value()); + assert(e1.error() == 5); + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp @@ -0,0 +1,290 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected& operator=(const expected& rhs); +// +// Effects: +// - If this->has_value() && rhs.has_value() is true, equivalent to val = *rhs. +// - Otherwise, if this->has_value() is true, equivalent to: +// reinit-expected(unex, val, rhs.error()) +// - Otherwise, if rhs.has_value() is true, equivalent to: +// reinit-expected(val, unex, *rhs) +// - Otherwise, equivalent to unex = rhs.error(). +// +// - Then, if no exception was thrown, equivalent to: has_val = rhs.has_value(); return *this; +// +// Returns: *this. +// +// Remarks: This operator is defined as deleted unless: +// - is_copy_assignable_v is true and +// - is_copy_constructible_v is true and +// - is_copy_assignable_v is true and +// - is_copy_constructible_v is true and +// - is_nothrow_move_constructible_v || is_nothrow_move_constructible_v is true. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotCopyConstructible { + NotCopyConstructible(const NotCopyConstructible&) = delete; + NotCopyConstructible& operator=(const NotCopyConstructible&) = default; +}; + +struct NotCopyAssignable { + NotCopyAssignable(const NotCopyAssignable&) = default; + NotCopyAssignable& operator=(const NotCopyAssignable&) = delete; +}; + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow const&) = default; + MoveMayThrow& operator=(const MoveMayThrow&) = default; + MoveMayThrow(MoveMayThrow&&) noexcept(false) {} + MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; } +}; + +// Test constraints +static_assert(std::is_copy_assignable_v>); + +// !is_copy_assignable_v +static_assert(!std::is_copy_assignable_v>); + +// !is_copy_constructible_v +static_assert(!std::is_copy_assignable_v>); + +// !is_copy_assignable_v +static_assert(!std::is_copy_assignable_v>); + +// !is_copy_constructible_v +static_assert(!std::is_copy_assignable_v>); + +// !is_nothrow_move_constructible_v && is_nothrow_move_constructible_v +static_assert(std::is_copy_assignable_v>); + +// is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v +static_assert(std::is_copy_assignable_v>); + +// !is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v +static_assert(!std::is_copy_assignable_v>); + +constexpr bool test() { + // If this->has_value() && rhs.has_value() is true, equivalent to val = *rhs. + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::in_place, oldState, 5); + const std::expected e2(std::in_place, newState, 10); + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + assert(oldState.copyAssignCalled); + } + + // - Otherwise, if this->has_value() is true, equivalent to: + // reinit-expected(unex, val, rhs.error()) + // E move is not noexcept + // In this case, it should call the branch + // + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + // + { + TracedNoexcept::state oldState{}; + Traced::state newState{}; + std::expected e1(std::in_place, oldState, 5); + const std::expected e2(std::unexpect, newState, 10); + + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + + assert(!oldState.copyAssignCalled); + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!oldState.copyCtorCalled); + assert(newState.copyCtorCalled); + assert(!newState.moveCtorCalled); + assert(!newState.dtorCalled); + } + + // - Otherwise, if this->has_value() is true, equivalent to: + // reinit-expected(unex, val, rhs.error()) + // E move is noexcept + // In this case, it should call the branch + // + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + // + { + Traced::state oldState{}; + TracedNoexcept::state newState{}; + std::expected e1(std::in_place, oldState, 5); + const std::expected e2(std::unexpect, newState, 10); + + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + + assert(!oldState.copyAssignCalled); + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!oldState.copyCtorCalled); + assert(newState.copyCtorCalled); + assert(!newState.moveCtorCalled); + assert(!newState.dtorCalled); + } + + // - Otherwise, if rhs.has_value() is true, equivalent to: + // reinit-expected(val, unex, *rhs) + // T move is not noexcept + // In this case, it should call the branch + // + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + // + { + TracedNoexcept::state oldState{}; + Traced::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + const std::expected e2(std::in_place, newState, 10); + + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.copyAssignCalled); + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!oldState.copyCtorCalled); + assert(newState.copyCtorCalled); + assert(!newState.moveCtorCalled); + assert(!newState.dtorCalled); + } + + // - Otherwise, if rhs.has_value() is true, equivalent to: + // reinit-expected(val, unex, *rhs) + // T move is noexcept + // In this case, it should call the branch + // + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + // + { + Traced::state oldState{}; + TracedNoexcept::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + const std::expected e2(std::in_place, newState, 10); + + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.copyAssignCalled); + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!oldState.copyCtorCalled); + assert(newState.copyCtorCalled); + assert(!newState.moveCtorCalled); + assert(!newState.dtorCalled); + } + + // Otherwise, equivalent to unex = rhs.error(). + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + const std::expected e2(std::unexpect, newState, 10); + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + assert(oldState.copyAssignCalled); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowOnCopy { + ThrowOnCopy() = default; + ThrowOnCopy(const ThrowOnCopy&) { throw Except{}; }; + ThrowOnCopy& operator=(const ThrowOnCopy&) = default; + ThrowOnCopy(ThrowOnCopy&&) noexcept(false) {} + }; + + // assign value throw on copy + { + std::expected e1(std::unexpect, 5); + const std::expected e2(std::in_place); + try { + e1 = e2; + assert(false); + } catch (Except) { + assert(!e1.has_value()); + assert(e1.error() == 5); + } + } + + // assign error throw on copy + { + std::expected e1(5); + const std::expected e2(std::unexpect); + try { + e1 = e2; + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(e1.value() == 5); + } + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp @@ -0,0 +1,307 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected& operator=(expected&& rhs) noexcept(see below); +// +// Constraints: +// - is_move_constructible_v is true and +// - is_move_assignable_v is true and +// - is_move_constructible_v is true and +// - is_move_assignable_v is true and +// - is_nothrow_move_constructible_v || is_nothrow_move_constructible_v is true. +// +// Effects: +// - If this->has_value() && rhs.has_value() is true, equivalent to val = std::move(*rhs). +// - Otherwise, if this->has_value() is true, equivalent to: +// reinit-expected(unex, val, std::move(rhs.error())) +// - Otherwise, if rhs.has_value() is true, equivalent to: +// reinit-expected(val, unex, std::move(*rhs)) +// - Otherwise, equivalent to unex = std::move(rhs.error()). +// - Then, if no exception was thrown, equivalent to: has_val = rhs.has_value(); return *this; +// +// Returns: *this. +// +// Remarks: The exception specification is equivalent to: +// is_nothrow_move_assignable_v && is_nothrow_move_constructible_v && +// is_nothrow_move_assignable_v && is_nothrow_move_constructible_v + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotMoveConstructible { + NotMoveConstructible(NotMoveConstructible&&) = delete; + NotMoveConstructible& operator=(NotMoveConstructible&&) = default; +}; + +struct NotMoveAssignable { + NotMoveAssignable(NotMoveAssignable&&) = default; + NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; +}; + +struct MoveCtorMayThrow { + MoveCtorMayThrow(MoveCtorMayThrow&&) noexcept(false) {} + MoveCtorMayThrow& operator=(MoveCtorMayThrow&&) noexcept = default; +}; + +// Test constraints +static_assert(std::is_move_assignable_v>); + +// !is_move_assignable_v +static_assert(!std::is_move_assignable_v>); + +// !is_move_constructible_v +static_assert(!std::is_move_assignable_v>); + +// !is_move_assignable_v +static_assert(!std::is_move_assignable_v>); + +// !is_move_constructible_v +static_assert(!std::is_move_assignable_v>); + +// !is_nothrow_move_constructible_v && is_nothrow_move_constructible_v +static_assert(std::is_move_assignable_v>); + +// is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v +static_assert(std::is_move_assignable_v>); + +// !is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v +static_assert(!std::is_move_assignable_v>); + +struct MoveAssignMayThrow { + MoveAssignMayThrow(MoveAssignMayThrow&&) noexcept = default; + MoveAssignMayThrow& operator=(MoveAssignMayThrow&&) noexcept(false) { return *this; } +}; + +// Test noexcept +static_assert(std::is_nothrow_move_assignable_v>); + +// !is_nothrow_move_assignable_v +static_assert(!std::is_nothrow_move_assignable_v>); + +// !is_nothrow_move_constructible_v +static_assert(!std::is_nothrow_move_assignable_v>); + +// !is_nothrow_move_assignable_v +static_assert(!std::is_nothrow_move_assignable_v>); + +// !is_nothrow_move_constructible_v +static_assert(!std::is_nothrow_move_assignable_v>); + +constexpr bool test() { + // If this->has_value() && rhs.has_value() is true, equivalent to val = std::move(*rhs). + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::in_place, oldState, 5); + std::expected e2(std::in_place, newState, 10); + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + assert(oldState.moveAssignCalled); + } + + // - Otherwise, if this->has_value() is true, equivalent to: + // reinit-expected(unex, val, rhs.error()) + // E move is not noexcept + // In this case, it should call the branch + // + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + // + { + TracedNoexcept::state oldState{}; + Traced::state newState{}; + std::expected e1(std::in_place, oldState, 5); + std::expected e2(std::unexpect, newState, 10); + + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + + assert(!oldState.moveAssignCalled); + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!oldState.copyCtorCalled); + assert(!newState.copyCtorCalled); + assert(newState.moveCtorCalled); + assert(!newState.dtorCalled); + } + + // - Otherwise, if this->has_value() is true, equivalent to: + // reinit-expected(unex, val, rhs.error()) + // E move is noexcept + // In this case, it should call the branch + // + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + // + { + Traced::state oldState{}; + TracedNoexcept::state newState{}; + std::expected e1(std::in_place, oldState, 5); + std::expected e2(std::unexpect, newState, 10); + + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!oldState.copyCtorCalled); + assert(!newState.copyCtorCalled); + assert(newState.moveCtorCalled); + assert(!newState.dtorCalled); + } + + // - Otherwise, if rhs.has_value() is true, equivalent to: + // reinit-expected(val, unex, *rhs) + // T move is not noexcept + // In this case, it should call the branch + // + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + // + { + TracedNoexcept::state oldState{}; + Traced::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + std::expected e2(std::in_place, newState, 10); + + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!oldState.copyCtorCalled); + assert(!newState.copyCtorCalled); + assert(newState.moveCtorCalled); + assert(!newState.dtorCalled); + } + + // - Otherwise, if rhs.has_value() is true, equivalent to: + // reinit-expected(val, unex, *rhs) + // T move is noexcept + // In this case, it should call the branch + // + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + // + { + Traced::state oldState{}; + TracedNoexcept::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + std::expected e2(std::in_place, newState, 10); + + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(e1.has_value()); + assert(e1.value().data_ == 10); + + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!oldState.copyCtorCalled); + assert(!newState.copyCtorCalled); + assert(newState.moveCtorCalled); + assert(!newState.dtorCalled); + } + + // Otherwise, equivalent to unex = rhs.error(). + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + std::expected e2(std::unexpect, newState, 10); + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + assert(oldState.moveAssignCalled); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowOnMove { + ThrowOnMove() = default; + ThrowOnMove(ThrowOnMove&&) { throw Except{}; }; + ThrowOnMove& operator=(ThrowOnMove&&) = default; + }; + + // assign value throw on move + { + std::expected e1(std::unexpect, 5); + std::expected e2(std::in_place); + try { + e1 = std::move(e2); + assert(false); + } catch (Except) { + assert(!e1.has_value()); + assert(e1.error() == 5); + } + } + + // assign error throw on move + { + std::expected e1(5); + std::expected e2(std::unexpect); + try { + e1 = std::move(e2); + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(*e1 == 5); + } + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.unexpected.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.unexpected.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.unexpected.copy.pass.cpp @@ -0,0 +1,209 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr expected& operator=(const unexpected& e); +// +// Let GF be const G& +// Constraints: +// - is_constructible_v is true; and +// - is_assignable_v is true; and +// - is_nothrow_constructible_v || is_nothrow_move_constructible_v || +// is_nothrow_move_constructible_v is true. +// +// Effects: +// - If has_value() is true, equivalent to: +// reinit-expected(unex, val, std::forward(e.error())); +// has_val = false; +// - Otherwise, equivalent to: unex = std::forward(e.error()); +// Returns: *this. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotCopyConstructible { + NotCopyConstructible(const NotCopyConstructible&) = delete; + NotCopyConstructible& operator=(const NotCopyConstructible&) = default; +}; + +struct NotCopyAssignable { + NotCopyAssignable(const NotCopyAssignable&) = default; + NotCopyAssignable& operator=(const NotCopyAssignable&) = delete; +}; + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow const&) = default; + MoveMayThrow& operator=(const MoveMayThrow&) = default; + MoveMayThrow(MoveMayThrow&&) noexcept(false) {} + MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; } +}; + +// Test constraints +static_assert(std::is_assignable_v&, const std::unexpected&>); + +// !is_constructible_v +static_assert( + !std::is_assignable_v&, const std::unexpected&>); + +// !is_assignable_v +static_assert(!std::is_assignable_v&, const std::unexpected&>); + +template +struct MaybeNoexcept { + explicit MaybeNoexcept(int) noexcept(convertNoexcept); + MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept); + MaybeNoexcept& operator=(MaybeNoexcept&&) = default; + MaybeNoexcept& operator=(int); +}; + +// !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + const std::unexpected&>); + +// is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + const std::unexpected&>); + +// !is_nothrow_constructible_v && is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + const std::unexpected&>); + +// !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(!std::is_assignable_v, MaybeNoexcept>&, + const std::unexpected&>); + +constexpr bool test() { + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // is_nothrow_constructible_v + // + // In this case, it should call the branch + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + const std::unexpected un(10); + decltype(auto) x = (e = un); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e.error().copiedFromInt); + } + + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // !is_nothrow_constructible_v && is_nothrow_move_constructible_v + // + // In this case, it should call the branch + // T tmp(std::forward(args)...); + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::move(tmp)); + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + const std::unexpected un(10); + decltype(auto) x = (e = un); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!e.error().copiedFromInt); + assert(e.error().movedFromTmp); + } + + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // !is_nothrow_constructible_v && !is_nothrow_move_constructible_v + // is_nothrow_move_constructible_v + // + // In this case, it should call the branch + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + const std::unexpected un(10); + decltype(auto) x = (e = un); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e.error().copiedFromInt); + } + + // Otherwise, equivalent to: unex = std::forward(e.error()); + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + const std::unexpected e(std::in_place, newState, 10); + decltype(auto) x = (e1 = e); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + assert(oldState.copyAssignCalled); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowOnConvert { + ThrowOnConvert() = default; + ThrowOnConvert(const int&) { throw Except{}; } + ThrowOnConvert(int&&) {} + ThrowOnConvert(const ThrowOnConvert&) noexcept(false) {} + ThrowOnConvert& operator=(const ThrowOnConvert&) = default; + ThrowOnConvert(ThrowOnConvert&&) noexcept(false) {} + ThrowOnConvert& operator=(ThrowOnConvert&&) = default; + }; + + std::expected e1(std::in_place, 5); + const std::unexpected un(10); + try { + e1 = un; + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(*e1 == 5); + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.unexpected.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.unexpected.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.unexpected.move.pass.cpp @@ -0,0 +1,209 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr expected& operator=(unexpected&& e); +// +// Let GF be G +// Constraints: +// - is_constructible_v is true; and +// - is_assignable_v is true; and +// - is_nothrow_constructible_v || is_nothrow_move_constructible_v || +// is_nothrow_move_constructible_v is true. +// +// Effects: +// - If has_value() is true, equivalent to: +// reinit-expected(unex, val, std::forward(e.error())); +// has_val = false; +// - Otherwise, equivalent to: unex = std::forward(e.error()); +// Returns: *this. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotMoveConstructible { + NotMoveConstructible(NotMoveConstructible&&) = delete; + NotMoveConstructible& operator=(NotMoveConstructible&&) = default; +}; + +struct NotMoveAssignable { + NotMoveAssignable(NotMoveAssignable&&) = default; + NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; +}; + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow const&) = default; + MoveMayThrow& operator=(const MoveMayThrow&) = default; + MoveMayThrow(MoveMayThrow&&) noexcept(false) {} + MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; } +}; + +// Test constraints +static_assert(std::is_assignable_v&, std::unexpected&&>); + +// !is_constructible_v +static_assert( + !std::is_assignable_v&, std::unexpected&&>); + +// !is_assignable_v +static_assert(!std::is_assignable_v&, std::unexpected&&>); + +template +struct MaybeNoexcept { + explicit MaybeNoexcept(int) noexcept(convertNoexcept); + MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept); + MaybeNoexcept& operator=(MaybeNoexcept&&) = default; + MaybeNoexcept& operator=(int); +}; + +// !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + std::unexpected&&>); + +// is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + std::unexpected&&>); + +// !is_nothrow_constructible_v && is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + std::unexpected&&>); + +// !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(!std::is_assignable_v, MaybeNoexcept>&, + std::unexpected&&>); + +constexpr bool test() { + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // is_nothrow_constructible_v + // + // In this case, it should call the branch + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + std::unexpected un(10); + decltype(auto) x = (e = std::move(un)); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e.error().movedFromInt); + } + + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // !is_nothrow_constructible_v && is_nothrow_move_constructible_v + // + // In this case, it should call the branch + // T tmp(std::forward(args)...); + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::move(tmp)); + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + std::unexpected un(10); + decltype(auto) x = (e = std::move(un)); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!e.error().movedFromInt); + assert(e.error().movedFromTmp); + } + + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // !is_nothrow_constructible_v && !is_nothrow_move_constructible_v + // is_nothrow_move_constructible_v + // + // In this case, it should call the branch + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + std::unexpected un(10); + decltype(auto) x = (e = std::move(un)); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e.error().movedFromInt); + } + + // Otherwise, equivalent to: unex = std::forward(e.error()); + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + std::unexpected e(std::in_place, newState, 10); + decltype(auto) x = (e1 = std::move(e)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + assert(oldState.moveAssignCalled); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowOnConvert { + ThrowOnConvert() = default; + ThrowOnConvert(const int&) {} + ThrowOnConvert(int&&) { throw Except{}; } + ThrowOnConvert(const ThrowOnConvert&) noexcept(false) {} + ThrowOnConvert& operator=(const ThrowOnConvert&) = default; + ThrowOnConvert(ThrowOnConvert&&) noexcept(false) {} + ThrowOnConvert& operator=(ThrowOnConvert&&) = default; + }; + + std::expected e1(std::in_place, 5); + std::unexpected un(10); + try { + e1 = std::move(un); + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(*e1 == 5); + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.intializer_list.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.intializer_list.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.intializer_list.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr T& emplace(initializer_list il, Args&&... args) noexcept; +// Constraints: is_nothrow_constructible_v&, Args...> is true. +// +// Effects: Equivalent to: +// if (has_value()) { +// destroy_at(addressof(val)); +// } else { +// destroy_at(addressof(unex)); +// has_val = true; +// } +// return *construct_at(addressof(val), il, std::forward(args)...); + +#include +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +template +concept CanEmplace = requires(T t, Args&&... args) { t.emplace(std::forward(args)...); }; + +static_assert(CanEmplace, int>); + +template +struct CtorFromInitalizerList { + CtorFromInitalizerList(std::initializer_list&) noexcept(Noexcept); + CtorFromInitalizerList(std::initializer_list&, int) noexcept(Noexcept); +}; + +static_assert(CanEmplace, int>, std::initializer_list&>); +static_assert(!CanEmplace, int>, std::initializer_list&>); +static_assert(CanEmplace, int>, std::initializer_list&, int>); +static_assert(!CanEmplace, int>, std::initializer_list&, int>); + +struct Data { + std::initializer_list il; + int i; + + constexpr Data(std::initializer_list& l, int ii) noexcept : il(l), i(ii) {} +}; + +constexpr bool test() { + // has_value + { + auto list1 = {1, 2, 3}; + auto list2 = {4, 5, 6}; + std::expected e(std::in_place, list1, 5); + decltype(auto) x = e.emplace(list2, 10); + static_assert(std::same_as); + assert(&x == &(*e)); + + assert(e.has_value()); + assert(std::ranges::equal(e.value().il, list2)); + assert(e.value().i == 10); + } + + // !has_value + { + auto list = {4, 5, 6}; + std::expected e(std::unexpect, 5); + decltype(auto) x = e.emplace(list, 10); + static_assert(std::same_as); + assert(&x == &(*e)); + + assert(e.has_value()); + assert(std::ranges::equal(e.value().il, list)); + assert(e.value().i == 10); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr T& emplace(Args&&... args) noexcept; +// Constraints: is_nothrow_constructible_v is true. +// +// Effects: Equivalent to: +// if (has_value()) { +// destroy_at(addressof(val)); +// } else { +// destroy_at(addressof(unex)); +// has_val = true; +// } +// return *construct_at(addressof(val), std::forward(args)...); + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +template +concept CanEmplace = requires(T t, Args&&... args) { t.emplace(std::forward(args)...); }; + +static_assert(CanEmplace, int>); + +template +struct CtorFromInt { + CtorFromInt(int) noexcept(Noexcept); + CtorFromInt(int, int) noexcept(Noexcept); +}; + +static_assert(CanEmplace, int>, int>); +static_assert(CanEmplace, int>, int, int>); +static_assert(!CanEmplace, int>, int>); +static_assert(!CanEmplace, int>, int, int>); + +constexpr bool test() { + // has_value + { + BothNoexcept::state oldState{}; + BothNoexcept::state newState{}; + std::expected e(std::in_place, oldState, 5); + decltype(auto) x = e.emplace(newState, 10); + static_assert(std::same_as); + assert(&x == &(*e)); + + assert(oldState.dtorCalled); + assert(e.has_value()); + assert(e.value().data_ == 10); + } + + // !has_value + { + BothMayThrow::state oldState{}; + std::expected e(std::unexpect, oldState, 5); + decltype(auto) x = e.emplace(10); + static_assert(std::same_as); + assert(&x == &(*e)); + + assert(oldState.dtorCalled); + assert(e.has_value()); + assert(e.value() == 10); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.convert.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.convert.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.convert.copy.pass.cpp @@ -0,0 +1,203 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(see below) expected(const expected&); +// +// Let: +// - UF be const U& +// - GF be const G& +// +// Constraints: +// - is_constructible_v is true; and +// - is_constructible_v is true; and +// - is_constructible_v&> is false; and +// - is_constructible_v> is false; and +// - is_constructible_v&> is false; and +// - is_constructible_v> is false; and +// - is_convertible_v&, T> is false; and +// - is_convertible_v&&, T> is false; and +// - is_convertible_v&, T> is false; and +// - is_convertible_v&&, T> is false; and +// - is_constructible_v, expected&> is false; and +// - is_constructible_v, expected> is false; and +// - is_constructible_v, const expected&> is false; and +// - is_constructible_v, const expected> is false. +// +// Effects: If rhs.has_value(), direct-non-list-initializes val with std::forward(*rhs). Otherwise, direct-non-list-initializes unex with std::forward(rhs.error()). +// +// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true. +// +// Throws: Any exception thrown by the initialization of val or unex. +// +// Remarks: The expression inside explicit is equivalent to !is_convertible_v || !is_convertible_v. + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test Constraints: +template +concept canCstrFromExpected = std::is_constructible_v, const std::expected&>; + +struct CtorFromInt { + CtorFromInt(int); +}; + +static_assert(canCstrFromExpected); + +struct NoCtorFromInt {}; + +// !is_constructible_v +static_assert(!canCstrFromExpected); + +// !is_constructible_v +static_assert(!canCstrFromExpected); + +template +struct CtorFrom { + explicit CtorFrom(int) + requires(!std::same_as); + explicit CtorFrom(T); + explicit CtorFrom(auto&&) = delete; +}; + +// is_constructible_v&> +static_assert(!canCstrFromExpected&>, int, int, int>); + +// is_constructible_v> +static_assert(!canCstrFromExpected&&>, int, int, int>); + +// is_constructible_v&> +// note that this is true because it is covered by the other overload +// template constexpr explicit(see below) expected(U&& v); +// The fact that it is not ambiguous proves that the overload under testing is removed +static_assert(canCstrFromExpected const&>, int, int, int>); + +// is_constructible_v> +static_assert(!canCstrFromExpected const&&>, int, int, int>); + +template +struct ConvertFrom { + ConvertFrom(int) + requires(!std::same_as); + ConvertFrom(T); + ConvertFrom(auto&&) = delete; +}; + +// is_convertible_v&, T> +static_assert(!canCstrFromExpected&>, int, int, int>); + +// is_convertible_v&&, T> +static_assert(!canCstrFromExpected&&>, int, int, int>); + +// is_convertible_v&, T> +// note that this is true because it is covered by the other overload +// template constexpr explicit(see below) expected(U&& v); +// The fact that it is not ambiguous proves that the overload under testing is removed +static_assert(canCstrFromExpected const&>, int, int, int>); + +// is_convertible_v&&, T> +static_assert(!canCstrFromExpected const&&>, int, int, int>); + +// Note for below 4 tests, because their E is constructible from cvref of std::expected, +// unexpected will be constructible from cvref of std::expected +// is_constructible_v, expected&> +static_assert(!canCstrFromExpected&>, int, int>); + +// is_constructible_v, expected> +static_assert(!canCstrFromExpected&&>, int, int>); + +// is_constructible_v, const expected&> is false +static_assert(!canCstrFromExpected const&>, int, int>); + +// is_constructible_v, const expected> +static_assert(!canCstrFromExpected const&&>, int, int>); + +// test explicit +static_assert(std::is_convertible_v&, std::expected>); + +// !is_convertible_v +static_assert(std::is_constructible_v, int>, const std::expected&>); +static_assert(!std::is_convertible_v&, std::expected, int>>); + +// !is_convertible_v. +static_assert(std::is_constructible_v>, const std::expected&>); +static_assert(!std::is_convertible_v&, std::expected>>); + +struct Data { + int i; + constexpr Data(int ii) : i(ii) {} +}; + +constexpr bool test() { + // convert the value + { + const std::expected e1(5); + std::expected e2 = e1; + assert(e2.has_value()); + assert(e2.value().i == 5); + assert(e1.has_value()); + assert(e1.value() == 5); + } + + // convert the error + { + const std::expected e1(std::unexpect, 5); + std::expected e2 = e1; + assert(!e2.has_value()); + assert(e2.error().i == 5); + assert(!e1.has_value()); + assert(e1.error() == 5); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowingInt { + ThrowingInt(int) { throw Except{}; } + }; + + // throw on converting value + { + const std::expected e1; + try { + [[maybe_unused]] std::expected e2 = e1; + assert(false); + } catch (Except) { + } + } + + // throw on converting error + { + const std::expected e1(std::unexpect); + try { + [[maybe_unused]] std::expected e2 = e1; + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.convert.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.convert.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.convert.move.pass.cpp @@ -0,0 +1,202 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(see below) expected(expected&&); +// +// Let: +// - UF be const U +// - GF be const G +// +// Constraints: +// - is_constructible_v is true; and +// - is_constructible_v is true; and +// - is_constructible_v&> is false; and +// - is_constructible_v> is false; and +// - is_constructible_v&> is false; and +// - is_constructible_v> is false; and +// - is_convertible_v&, T> is false; and +// - is_convertible_v&&, T> is false; and +// - is_convertible_v&, T> is false; and +// - is_convertible_v&&, T> is false; and +// - is_constructible_v, expected&> is false; and +// - is_constructible_v, expected> is false; and +// - is_constructible_v, const expected&> is false; and +// - is_constructible_v, const expected> is false. +// +// Effects: If rhs.has_value(), direct-non-list-initializes val with std::forward(*rhs). Otherwise, direct-non-list-initializes unex with std::forward(rhs.error()). +// +// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true. +// +// Throws: Any exception thrown by the initialization of val or unex. +// +// Remarks: The expression inside explicit is equivalent to !is_convertible_v || !is_convertible_v. + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +template +concept canCstrFromExpected = std::is_constructible_v, std::expected&&>; + +struct CtorFromInt { + CtorFromInt(int); +}; + +static_assert(canCstrFromExpected); + +struct NoCtorFromInt {}; + +// !is_constructible_v +static_assert(!canCstrFromExpected); + +// !is_constructible_v +static_assert(!canCstrFromExpected); + +template +struct CtorFrom { + explicit CtorFrom(int) + requires(!std::same_as); + explicit CtorFrom(T); + explicit CtorFrom(auto&&) = delete; +}; + +// is_constructible_v&> +static_assert(!canCstrFromExpected&>, int, int, int>); + +// is_constructible_v> +// note that this is true because it is covered by the other overload +// template constexpr explicit(see below) expected(U&& v); +// The fact that it is not ambiguous proves that the overload under testing is removed +static_assert(canCstrFromExpected&&>, int, int, int>); + +// is_constructible_v&> +static_assert(!canCstrFromExpected const&>, int, int, int>); + +// is_constructible_v> +static_assert(!canCstrFromExpected const&&>, int, int, int>); + +template +struct ConvertFrom { + ConvertFrom(int) + requires(!std::same_as); + ConvertFrom(T); + ConvertFrom(auto&&) = delete; +}; + +// is_convertible_v&, T> +static_assert(!canCstrFromExpected&>, int, int, int>); + +// is_convertible_v&&, T> +// note that this is true because it is covered by the other overload +// template constexpr explicit(see below) expected(U&& v); +// The fact that it is not ambiguous proves that the overload under testing is removed +static_assert(canCstrFromExpected&&>, int, int, int>); + +// is_convertible_v&, T> +static_assert(!canCstrFromExpected const&>, int, int, int>); + +// is_convertible_v&&, T> +static_assert(!canCstrFromExpected const&&>, int, int, int>); + +// is_constructible_v, expected&> +static_assert(!canCstrFromExpected&>, int, int>); + +// is_constructible_v, expected> +static_assert(!canCstrFromExpected&&>, int, int>); + +// is_constructible_v, const expected&> is false +static_assert(!canCstrFromExpected const&>, int, int>); + +// is_constructible_v, const expected> +static_assert(!canCstrFromExpected const&&>, int, int>); + +// test explicit +static_assert(std::is_convertible_v&&, std::expected>); + +// !is_convertible_v +static_assert(std::is_constructible_v, int>, std::expected&&>); +static_assert(!std::is_convertible_v&&, std::expected, int>>); + +// !is_convertible_v. +static_assert(std::is_constructible_v>, std::expected&&>); +static_assert(!std::is_convertible_v&&, std::expected>>); + +struct Data { + MoveOnly data; + constexpr Data(MoveOnly&& m) : data(std::move(m)) {} +}; + +constexpr bool test() { + // convert the value + { + std::expected e1(5); + std::expected e2 = std::move(e1); + assert(e2.has_value()); + assert(e2.value().data.get() == 5); + assert(e1.has_value()); + assert(e1.value().get() == 0); + } + + // convert the error + { + std::expected e1(std::unexpect, 5); + std::expected e2 = std::move(e1); + assert(!e2.has_value()); + assert(e2.error().data.get() == 5); + assert(!e1.has_value()); + assert(e1.error().get() == 0); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowingInt { + ThrowingInt(int) { throw Except{}; } + }; + + // throw on converting value + { + const std::expected e1; + try { + [[maybe_unused]] std::expected e2 = e1; + assert(false); + } catch (Except) { + } + } + + // throw on converting error + { + const std::expected e1(std::unexpect); + try { + [[maybe_unused]] std::expected e2 = e1; + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.copy.pass.cpp @@ -0,0 +1,138 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected(const expected& rhs); +// +// Effects: If rhs.has_value() is true, direct-non-list-initializes val with *rhs. +// Otherwise, direct-non-list-initializes unex with rhs.error(). +// +// Postconditions: rhs.has_value() == this->has_value(). +// +// Throws: Any exception thrown by the initialization of val or unex. +// +// Remarks: This constructor is defined as deleted unless +// - is_copy_constructible_v is true and +// - is_copy_constructible_v is true. +// +// This constructor is trivial if +// - is_trivially_copy_constructible_v is true and +// - is_trivially_copy_constructible_v is true. + +#include +#include +#include +#include + +#include "test_macros.h" + +struct NonCopyable { + NonCopyable(const NonCopyable&) = delete; +}; + +struct CopyableNonTrivial { + int i; + constexpr CopyableNonTrivial(int ii) : i(ii) {} + constexpr CopyableNonTrivial(const CopyableNonTrivial& o) { i = o.i; } + friend constexpr bool operator==(const CopyableNonTrivial&, const CopyableNonTrivial&) = default; +}; + +// Test: This constructor is defined as deleted unless +// - is_copy_constructible_v is true and +// - is_copy_constructible_v is true. +static_assert(std::is_copy_constructible_v>); +static_assert(std::is_copy_constructible_v>); +static_assert(std::is_copy_constructible_v>); +static_assert(std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); + +// Test: This constructor is trivial if +// - is_trivially_copy_constructible_v is true and +// - is_trivially_copy_constructible_v is true. +#if __cpp_concepts >= 202002 +static_assert(std::is_trivially_copy_constructible_v>); +#endif +static_assert(!std::is_trivially_copy_constructible_v>); +static_assert(!std::is_trivially_copy_constructible_v>); +static_assert(!std::is_trivially_copy_constructible_v>); + +constexpr bool test() { + // copy the value non-trivial + { + const std::expected e1(5); + auto e2 = e1; + assert(e2.has_value()); + assert(e2.value().i == 5); + } + + // copy the error non-trivial + { + const std::expected e1(std::unexpect, 5); + auto e2 = e1; + assert(!e2.has_value()); + assert(e2.error().i == 5); + } + + // copy the value trivial + { + const std::expected e1(5); + auto e2 = e1; + assert(e2.has_value()); + assert(e2.value() == 5); + } + + // copy the error trivial + { + const std::expected e1(std::unexpect, 5); + auto e2 = e1; + assert(!e2.has_value()); + assert(e2.error() == 5); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing() = default; + Throwing(const Throwing&) { throw Except{}; } + }; + + // throw on copying value + { + const std::expected e1; + try { + [[maybe_unused]] auto e2 = e1; + assert(false); + } catch (Except) { + } + } + + // throw on copying error + { + const std::expected e1(std::unexpect); + try { + [[maybe_unused]] auto e2 = e1; + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.default.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.default.pass.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// +// constexpr expected(); + +// Constraints: is_default_constructible_v is true. +// +// Effects: Value-initializes val. +// Postconditions: has_value() is true. +// +// Throws: Any exception thrown by the initialization of val. + +#include +#include +#include + +#include "test_macros.h" + +struct NoDedefaultCtor { + NoDedefaultCtor() = delete; +}; + +// Test constraints +static_assert(std::is_default_constructible_v>); +static_assert(!std::is_default_constructible_v>); + +struct MyInt { + int i; + friend constexpr bool operator==(const MyInt&, const MyInt&) = default; +}; + +template +constexpr void testDefaultCtor() { + std::expected e; + assert(e.has_value()); + assert(e.value() == T()); +} + +template +constexpr void testTypes() { + testDefaultCtor(); + testDefaultCtor(); +} + +constexpr bool test() { + testTypes(); + testTypes(); + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing() { throw Except{}; }; + }; + + try { + std::expected u; + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.inplace.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.inplace.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.inplace.pass.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit expected(in_place_t, Args&&... args); +// +// Constraints: is_constructible_v is true. +// +// Effects: Direct-non-list-initializes val with std::forward(args).... +// +// Postconditions: has_value() is true. +// +// Throws: Any exception thrown by the initialization of val. + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +static_assert(std::is_constructible_v, std::in_place_t>); +static_assert(std::is_constructible_v, std::in_place_t, int>); + +// !is_constructible_v +struct foo {}; +static_assert(!std::is_constructible_v, std::in_place_t, int>); + +// test explicit +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; +static_assert(ImplicitlyConstructible); + +static_assert(!ImplicitlyConstructible, std::in_place_t>); +static_assert(!ImplicitlyConstructible, std::in_place_t, int>); + +struct CopyOnly { + int i; + constexpr CopyOnly(int ii) : i(ii) {} + CopyOnly(const CopyOnly&) = default; + CopyOnly(CopyOnly&&) = delete; + friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; } +}; + +template +constexpr void testInt() { + std::expected e(std::in_place, 5); + assert(e.has_value()); + assert(e.value() == 5); +} + +template +constexpr void testLValue() { + T t(5); + std::expected e(std::in_place, t); + assert(e.has_value()); + assert(e.value() == 5); +} + +template +constexpr void testRValue() { + std::expected e(std::in_place, T(5)); + assert(e.has_value()); + assert(e.value() == 5); +} + +constexpr bool test() { + testInt(); + testInt(); + testInt(); + testLValue(); + testLValue(); + testRValue(); + testRValue(); + + // no arg + { + std::expected e(std::in_place); + assert(e.has_value()); + assert(e.value() == 0); + } + + // one arg + { + std::expected e(std::in_place, 5); + assert(e.has_value()); + assert(e.value() == 5); + } + + // multi args + { + std::expected, int> e(std::in_place, 1, 2, MoveOnly(3)); + assert(e.has_value()); + assert((e.value() == std::tuple(1, 2, MoveOnly(3)))); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; }; + }; + + try { + std::expected u(std::in_place, 5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.inplace_init_list.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.inplace_init_list.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.inplace_init_list.pass.cpp @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit expected(in_place_t, initializer_list il, Args&&... args); +// +// Constraints: is_constructible_v&, Args...> is true. +// +// Effects: Direct-non-list-initializes val with il, std::forward(args).... +// +// Postconditions: has_value() is true. +// +// Throws: Any exception thrown by the initialization of val. + +#include +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +static_assert( + std::is_constructible_v, int>, std::in_place_t, std::initializer_list>); + +// !is_constructible_v&, Args...> +static_assert(!std::is_constructible_v, std::in_place_t, std::initializer_list>); + +// test explicit +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; +static_assert(ImplicitlyConstructible); + +static_assert( + !ImplicitlyConstructible, int>, std::in_place_t, std::initializer_list>); + +template +struct Data { + std::vector vec_; + std::tuple tuple_; + + template + requires std::is_constructible_v, Us&&...> + constexpr Data(std::initializer_list il, Us&&... us) : vec_(il), tuple_(std::forward(us)...) {} +}; + +constexpr bool test() { + // no arg + { + std::expected, int> e(std::in_place, {1, 2, 3}); + assert(e.has_value()); + auto expectedList = {1, 2, 3}; + assert(std::ranges::equal(e.value().vec_, expectedList)); + } + + // one arg + { + std::expected, int> e(std::in_place, {4, 5, 6}, MoveOnly(5)); + assert(e.has_value()); + auto expectedList = {4, 5, 6}; + assert((std::ranges::equal(e.value().vec_, expectedList))); + assert(std::get<0>(e.value().tuple_) == 5); + } + + // multi args + { + int i = 5; + int j = 6; + MoveOnly m(7); + std::expected, int> e(std::in_place, {1, 2}, i, std::move(j), std::move(m)); + assert(e.has_value()); + auto expectedList = {1, 2}; + assert((std::ranges::equal(e.value().vec_, expectedList))); + assert(&std::get<0>(e.value().tuple_) == &i); + assert(&std::get<1>(e.value().tuple_) == &j); + assert(std::get<2>(e.value().tuple_) == 7); + assert(m.get() == 0); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(std::initializer_list, int) { throw Except{}; }; + }; + + try { + std::expected u(std::in_place, {1, 2}, 5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.move.pass.cpp @@ -0,0 +1,157 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected(expected&& rhs) noexcept(see below); +// +// Constraints: +// - is_move_constructible_v is true and +// - is_move_constructible_v is true. +// +// Effects: If rhs.has_value() is true, direct-non-list-initializes val with std::move(*rhs). +// Otherwise, direct-non-list-initializes unex with std::move(rhs.error()). +// +// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true. +// +// Throws: Any exception thrown by the initialization of val or unex. +// +// Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v && is_nothrow_move_constructible_v. +// +// This constructor is trivial if +// - is_trivially_move_constructible_v is true and +// - is_trivially_move_constructible_v is true. + +#include +#include +#include +#include + +#include "test_macros.h" + +struct NonMovable { + NonMovable(NonMovable&&) = delete; +}; + +struct MovableNonTrivial { + int i; + constexpr MovableNonTrivial(int ii) : i(ii) {} + constexpr MovableNonTrivial(MovableNonTrivial&& o) : i(o.i) { o.i = 0; } + friend constexpr bool operator==(const MovableNonTrivial&, const MovableNonTrivial&) = default; +}; + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow&&) {} +}; + +// Test Constraints: +// - is_move_constructible_v is true and +// - is_move_constructible_v is true. +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); +static_assert(!std::is_move_constructible_v>); +static_assert(!std::is_move_constructible_v>); +static_assert(!std::is_move_constructible_v>); + +// Test: This constructor is trivial if +// - is_trivially_move_constructible_v is true and +// - is_trivially_move_constructible_v is true. +#if __cpp_concepts >= 202002 +static_assert(std::is_trivially_move_constructible_v>); +#endif +static_assert(!std::is_trivially_move_constructible_v>); +static_assert(!std::is_trivially_move_constructible_v>); +static_assert(!std::is_trivially_move_constructible_v>); + +// Test: The exception specification is equivalent to +// is_nothrow_move_constructible_v && is_nothrow_move_constructible_v. +static_assert(std::is_nothrow_move_constructible_v>); +static_assert(!std::is_nothrow_move_constructible_v>); +static_assert(!std::is_nothrow_move_constructible_v>); +static_assert(!std::is_nothrow_move_constructible_v>); + +constexpr bool test() { + // move the value non-trivial + { + std::expected e1(5); + auto e2 = std::move(e1); + assert(e2.has_value()); + assert(e2.value().i == 5); + assert(e1.has_value()); + assert(e1.value().i == 0); + } + + // move the error non-trivial + { + std::expected e1(std::unexpect, 5); + auto e2 = std::move(e1); + assert(!e2.has_value()); + assert(e2.error().i == 5); + assert(!e1.has_value()); + assert(e1.error().i == 0); + } + + // move the value trivial + { + std::expected e1(5); + auto e2 = std::move(e1); + assert(e2.has_value()); + assert(e2.value() == 5); + assert(e1.has_value()); + } + + // move the error trivial + { + std::expected e1(std::unexpect, 5); + auto e2 = std::move(e1); + assert(!e2.has_value()); + assert(e2.error() == 5); + assert(!e1.has_value()); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing() = default; + Throwing(Throwing&&) { throw Except{}; } + }; + + // throw on moving value + { + std::expected e1; + try { + [[maybe_unused]] auto e2 = std::move(e1); + assert(false); + } catch (Except) { + } + } + + // throw on moving error + { + std::expected e1(std::unexpect); + try { + [[maybe_unused]] auto e2 = std::move(e1); + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(!is_convertible_v) expected(U&& v); +// +// Constraints: +// - is_same_v, in_place_t> is false; and +// - is_same_v> is false; and +// - remove_cvref_t is not a specialization of unexpected; and +// - is_constructible_v is true. +// +// Effects: Direct-non-list-initializes val with std::forward(v). +// +// Postconditions: has_value() is true. +// +// Throws: Any exception thrown by the initialization of val. + +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +static_assert(std::is_constructible_v, int>); + +// is_same_v, in_place_t> +struct FromJustInplace { + FromJustInplace(std::in_place_t); +}; +static_assert(!std::is_constructible_v, std::in_place_t>); +static_assert(!std::is_constructible_v, std::in_place_t const&>); + +// is_same_v> +// Note that result is true because it is covered by the constructors that take expected +static_assert(std::is_constructible_v, std::expected&>); + +// remove_cvref_t is a specialization of unexpected +// Note that result is true because it is covered by the constructors that take unexpected +static_assert(std::is_constructible_v, std::unexpected&>); + +// !is_constructible_v +struct foo {}; +static_assert(!std::is_constructible_v, foo>); + +// test explicit(!is_convertible_v) +struct NotConvertible { + explicit NotConvertible(int); +}; +static_assert(std::is_convertible_v>); +static_assert(!std::is_convertible_v>); + +struct CopyOnly { + int i; + constexpr CopyOnly(int ii) : i(ii) {} + CopyOnly(const CopyOnly&) = default; + CopyOnly(CopyOnly&&) = delete; + friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; } +}; + +template +constexpr void testInt() { + std::expected e(5); + assert(e.has_value()); + assert(e.value() == 5); +} + +template +constexpr void testLValue() { + T t(5); + std::expected e(t); + assert(e.has_value()); + assert(e.value() == 5); +} + +template +constexpr void testRValue() { + std::expected e(T(5)); + assert(e.has_value()); + assert(e.value() == 5); +} + +constexpr bool test() { + testInt(); + testInt(); + testInt(); + testLValue(); + testLValue(); + testRValue(); + testRValue(); + + // Test default template argument. + // Without it, the template parameter cannot be deduced from an initializer list + { + struct Bar { + int i; + int j; + constexpr Bar(int ii, int jj) : i(ii), j(jj) {} + }; + + std::expected e({5, 6}); + assert(e.value().i == 5); + assert(e.value().j == 6); + } + + // this is a confusing example, but the behaviour + // is exactly what is specified in the spec + { + struct BaseError {}; + struct DerivedError : BaseError {}; + + std::expected e1(false); + std::expected e2(e1); + assert(e2.has_value()); + assert(e2.value()); // yes, e2 holds "true" + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; }; + }; + + try { + std::expected u(5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpect.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpect.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpect.pass.cpp @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit expected(unexpect_t, Args&&... args); +// +// Constraints: is_constructible_v is true. +// +// Effects: Direct-non-list-initializes unex with std::forward(args).... +// +// Postconditions: has_value() is false. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +static_assert(std::is_constructible_v, std::unexpect_t>); +static_assert(std::is_constructible_v, std::unexpect_t, int>); + +// !is_constructible_v +struct foo {}; +static_assert(!std::is_constructible_v, std::unexpect_t, int>); + +// test explicit +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; +static_assert(ImplicitlyConstructible); + +static_assert(!ImplicitlyConstructible, std::unexpect_t>); +static_assert(!ImplicitlyConstructible, std::unexpect_t, int>); + +struct CopyOnly { + int i; + constexpr CopyOnly(int ii) : i(ii) {} + CopyOnly(const CopyOnly&) = default; + CopyOnly(CopyOnly&&) = delete; + friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; } +}; + +template +constexpr void testInt() { + std::expected e(std::unexpect, 5); + assert(!e.has_value()); + assert(e.error() == 5); +} + +template +constexpr void testLValue() { + T t(5); + std::expected e(std::unexpect, t); + assert(!e.has_value()); + assert(e.error() == 5); +} + +template +constexpr void testRValue() { + std::expected e(std::unexpect, T(5)); + assert(!e.has_value()); + assert(e.error() == 5); +} + +constexpr bool test() { + testInt(); + testInt(); + testInt(); + testLValue(); + testLValue(); + testRValue(); + testRValue(); + + // no arg + { + std::expected e(std::unexpect); + assert(!e.has_value()); + assert(e.error() == 0); + } + + // one arg + { + std::expected e(std::unexpect, 5); + assert(!e.has_value()); + assert(e.error() == 5); + } + + // multi args + { + std::expected> e(std::unexpect, 1, 2, MoveOnly(3)); + assert(!e.has_value()); + assert((e.error() == std::tuple(1, 2, MoveOnly(3)))); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; }; + }; + + try { + std::expected u(std::unexpect, 5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpect_init_list.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpect_init_list.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpect_init_list.pass.cpp @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit expected(unexpect_t, initializer_list il, Args&&... args); +// +// Constraints: is_constructible_v&, Args...> is true. +// +// Effects: Direct-non-list-initializes unex with il, std::forward(args).... +// +// Postconditions: has_value() is false. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +static_assert( + std::is_constructible_v>, std::unexpect_t, std::initializer_list>); + +// !is_constructible_v&, Args...> +static_assert(!std::is_constructible_v, std::unexpect_t, std::initializer_list>); + +// test explicit +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; +static_assert(ImplicitlyConstructible); + +static_assert( + !ImplicitlyConstructible>, std::unexpect_t, std::initializer_list>); + +template +struct Data { + std::vector vec_; + std::tuple tuple_; + + template + requires std::is_constructible_v, Us&&...> + constexpr Data(std::initializer_list il, Us&&... us) : vec_(il), tuple_(std::forward(us)...) {} +}; + +constexpr bool test() { + // no arg + { + std::expected> e(std::unexpect, {1, 2, 3}); + assert(!e.has_value()); + auto expectedList = {1, 2, 3}; + assert(std::ranges::equal(e.error().vec_, expectedList)); + } + + // one arg + { + std::expected> e(std::unexpect, {4, 5, 6}, MoveOnly(5)); + assert(!e.has_value()); + auto expectedList = {4, 5, 6}; + assert((std::ranges::equal(e.error().vec_, expectedList))); + assert(std::get<0>(e.error().tuple_) == 5); + } + + // multi args + { + int i = 5; + int j = 6; + MoveOnly m(7); + std::expected> e(std::unexpect, {1, 2}, i, std::move(j), std::move(m)); + assert(!e.has_value()); + auto expectedList = {1, 2}; + assert((std::ranges::equal(e.error().vec_, expectedList))); + assert(&std::get<0>(e.error().tuple_) == &i); + assert(&std::get<1>(e.error().tuple_) == &j); + assert(std::get<2>(e.error().tuple_) == 7); + assert(m.get() == 0); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(std::initializer_list, int) { throw Except{}; }; + }; + + try { + std::expected u(std::unexpect, {1, 2}, 5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpected.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpected.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpected.copy.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(!is_convertible_v) expected(const unexpected& e); +// +// Let GF be const G& +// +// Constraints: is_constructible_v is true. +// +// Effects: Direct-non-list-initializes unex with std::forward(e.error()). +// +// Postconditions: has_value() is false. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints +static_assert(std::is_constructible_v, const std::unexpected&>); + +// !is_constructible_v +struct foo {}; +static_assert(!std::is_constructible_v, const std::unexpected&>); +static_assert(!std::is_constructible_v, const std::unexpected&>); + +// explicit(!is_convertible_v) +struct NotConvertible { + explicit NotConvertible(int); +}; +static_assert(std::is_convertible_v&, std::expected>); +static_assert(!std::is_convertible_v&, std::expected>); + +struct MyInt { + int i; + constexpr MyInt(int ii) : i(ii) {} + friend constexpr bool operator==(const MyInt&, const MyInt&) = default; +}; + +template +constexpr void testUnexpected() { + const std::unexpected u(5); + std::expected e(u); + assert(!e.has_value()); + assert(e.error() == 5); +} + +constexpr bool test() { + testUnexpected(); + testUnexpected(); + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; } + }; + + { + const std::unexpected u(5); + try { + [[maybe_unused]] std::expected e(u); + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpected.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpected.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.unexpected.move.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(!is_convertible_v) expected(unexpected&& e); +// +// Let GF be G +// +// Constraints: is_constructible_v is true. +// +// Effects: Direct-non-list-initializes unex with std::forward(e.error()). +// +// Postconditions: has_value() is false. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints +static_assert(std::is_constructible_v, std::unexpected>); +static_assert(std::is_constructible_v, std::unexpected>); + +// !is_constructible_v +struct foo {}; +static_assert(!std::is_constructible_v, std::unexpected>); + +// explicit(!is_convertible_v) +struct NotConvertible { + explicit NotConvertible(int); +}; +static_assert(std::is_convertible_v&&, std::expected>); +static_assert(!std::is_convertible_v&&, std::expected>); + +struct MyInt { + int i; + constexpr MyInt(int ii) : i(ii) {} + friend constexpr bool operator==(const MyInt&, const MyInt&) = default; +}; + +template +constexpr void testInt() { + std::unexpected u(5); + std::expected e(std::move(u)); + assert(!e.has_value()); + assert(e.error() == 5); +} + +constexpr void testMoveOnly() { + std::unexpected u(MoveOnly(5)); + std::expected e(std::move(u)); + assert(!e.has_value()); + assert(e.error() == 5); + assert(u.error() == 0); +} + +constexpr bool test() { + testInt(); + testInt(); + testInt(); + testMoveOnly(); + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; } + }; + + { + std::unexpected u(5); + try { + [[maybe_unused]] std::expected e(std::move(u)); + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/dtor.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/dtor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/dtor.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr ~expected(); +// +// Effects: If has_value() is true, destroys val, otherwise destroys unex. +// +// Remarks: If is_trivially_destructible_v is true, and is_trivially_destructible_v is true, +// then this destructor is a trivial destructor. + +#include +#include +#include +#include + +#include "test_macros.h" + +// Test Remarks: If is_trivially_destructible_v is true, and is_trivially_destructible_v is true, +// then this destructor is a trivial destructor. +struct NonTrivial { + ~NonTrivial() {} +}; + +#if __cpp_concepts >= 202002 +static_assert(std::is_trivially_destructible_v>); +#endif +static_assert(!std::is_trivially_destructible_v>); +static_assert(!std::is_trivially_destructible_v>); +static_assert(!std::is_trivially_destructible_v>); + +struct TrackedDestroy { + bool& destroyed; + constexpr TrackedDestroy(bool& b) : destroyed(b) {} + constexpr ~TrackedDestroy() { destroyed = true; } +}; + +constexpr bool test() { + // has value + { + bool valueDestroyed = false; + { [[maybe_unused]] std::expected e(std::in_place, valueDestroyed); } + assert(valueDestroyed); + } + + // has error + { + bool errorDestroyed = false; + { [[maybe_unused]] std::expected e(std::unexpect, errorDestroyed); } + assert(errorDestroyed); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/equality/equality.T2.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.T2.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.T2.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template friend constexpr bool operator==(const expected& x, const T2& v); + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +struct Data { + int i; + constexpr Data(int ii) : i(ii) {} + + friend constexpr bool operator==(const Data& data, int ii) { return data.i == ii; } +}; + +constexpr bool test() { + // x.has_value() + { + const std::expected e1(std::in_place, 5); + int i2 = 10; + int i3 = 5; + assert(e1 != i2); + assert(e1 == i3); + } + + // !x.has_value() + { + const std::expected e1(std::unexpect, 5); + int i2 = 10; + int i3 = 5; + assert(e1 != i2); + assert(e1 != i3); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template requires (!is_void_v) +// friend constexpr bool operator==(const expected& x, const expected& y); + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test constraint +template +concept CanCompare = requires(T1 t1, T2 t2) { t1 == t2; }; + +struct Foo{}; +static_assert(!CanCompare); + +static_assert(CanCompare, std::expected>); +static_assert(CanCompare, std::expected>); + +// Note this is true because other overloads are unconstrained +static_assert(CanCompare, std::expected>); + +constexpr bool test() { + // x.has_value() && y.has_value() + { + const std::expected e1(5); + const std::expected e2(10); + const std::expected e3(5); + assert(e1 != e2); + assert(e1 == e3); + } + + // !x.has_value() && y.has_value() + { + const std::expected e1(std::unexpect, 5); + const std::expected e2(10); + const std::expected e3(5); + assert(e1 != e2); + assert(e1 != e3); + } + + // x.has_value() && !y.has_value() + { + const std::expected e1(5); + const std::expected e2(std::unexpect, 10); + const std::expected e3(std::unexpect, 5); + assert(e1 != e2); + assert(e1 != e3); + } + + // !x.has_value() && !y.has_value() + { + const std::expected e1(std::unexpect, 5); + const std::expected e2(std::unexpect, 10); + const std::expected e3(std::unexpect, 5); + assert(e1 != e2); + assert(e1 == e3); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/equality/equality.unexpected.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.unexpected.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.unexpected.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template friend constexpr bool operator==(const expected& x, const unexpected& e); + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +struct Data { + int i; + constexpr Data(int ii) : i(ii) {} + + friend constexpr bool operator==(const Data& data, int ii) { return data.i == ii; } +}; + +constexpr bool test() { + // x.has_value() + { + const std::expected e1(std::in_place, 5); + std::unexpected un2(10); + std::unexpected un3(5); + assert(e1 != un2); + assert(e1 != un3); + } + + // !x.has_value() + { + const std::expected e1(std::unexpect, 5); + std::unexpected un2(10); + std::unexpected un3(5); + assert(e1 != un2); + assert(e1 == un3); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/arrow.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/arrow.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/arrow.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const T* operator->() const noexcept; +// constexpr T* operator->() noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept ArrowNoexcept = + requires(T t) { + { t.operator->() } noexcept; + }; + +static_assert(!ArrowNoexcept); + +static_assert(ArrowNoexcept>); +static_assert(ArrowNoexcept>); + +constexpr bool test() { + // const + { + const std::expected e(5); + std::same_as decltype(auto) x = e.operator->(); + assert(x == &(e.value())); + assert(*x == 5); + } + + // non-const + { + std::expected e(5); + std::same_as decltype(auto) x = e.operator->(); + assert(x == &(e.value())); + assert(*x == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/bool.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/bool.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/bool.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr explicit operator bool() const noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept OpBoolNoexcept = + requires(T t) { + { static_cast(t) } noexcept; + }; + +struct Foo {}; +static_assert(!OpBoolNoexcept); + +static_assert(OpBoolNoexcept>); +static_assert(OpBoolNoexcept>); + +// Test explicit +static_assert(!std::is_convertible_v, bool>); + +constexpr bool test() { + // has_value + { + const std::expected e(5); + assert(static_cast(e)); + } + + // !has_value + { + const std::expected e(std::unexpect, 5); + assert(!static_cast(e)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/deref.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/deref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/deref.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const T& operator*() const & noexcept; +// constexpr T& operator*() & noexcept; +// constexpr T&& operator*() && noexcept; +// constexpr const T&& operator*() const && noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept DerefNoexcept = + requires(T t) { + { std::forward(t).operator*() } noexcept; + }; + +static_assert(!DerefNoexcept); + +static_assert(DerefNoexcept&>); +static_assert(DerefNoexcept&>); +static_assert(DerefNoexcept&&>); +static_assert(DerefNoexcept&&>); + +constexpr bool test() { + // non-const & + { + std::expected e(5); + decltype(auto) x = *e; + static_assert(std::same_as); + assert(&x == &(e.value())); + assert(x == 5); + } + + // const & + { + const std::expected e(5); + decltype(auto) x = *e; + static_assert(std::same_as); + assert(&x == &(e.value())); + assert(x == 5); + } + + // non-const && + { + std::expected e(5); + decltype(auto) x = *std::move(e); + static_assert(std::same_as); + assert(&x == &(e.value())); + assert(x == 5); + } + + // const && + { + const std::expected e(5); + decltype(auto) x = *std::move(e); + static_assert(std::same_as); + assert(&x == &(e.value())); + assert(x == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/error.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/error.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const E& error() const & noexcept; +// constexpr E& error() & noexcept; +// constexpr E&& error() && noexcept; +// constexpr const E&& error() const && noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept ErrorNoexcept = + requires(T t) { + { std::forward(t).error() } noexcept; + }; + +static_assert(!ErrorNoexcept); + +static_assert(ErrorNoexcept&>); +static_assert(ErrorNoexcept&>); +static_assert(ErrorNoexcept&&>); +static_assert(ErrorNoexcept&&>); + +constexpr bool test() { + // non-const & + { + std::expected e(std::unexpect, 5); + decltype(auto) x = e.error(); + static_assert(std::same_as); + assert(x == 5); + } + + // const & + { + const std::expected e(std::unexpect, 5); + decltype(auto) x = e.error(); + static_assert(std::same_as); + assert(x == 5); + } + + // non-const && + { + std::expected e(std::unexpect, 5); + decltype(auto) x = std::move(e).error(); + static_assert(std::same_as); + assert(x == 5); + } + + // const && + { + const std::expected e(std::unexpect, 5); + decltype(auto) x = std::move(e).error(); + static_assert(std::same_as); + assert(x == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/has_value.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/has_value.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/has_value.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr bool has_value() const noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept HasValueNoexcept = + requires(T t) { + { t.has_value() } noexcept; + }; + +struct Foo {}; +static_assert(!HasValueNoexcept); + +static_assert(HasValueNoexcept>); +static_assert(HasValueNoexcept>); + +constexpr bool test() { + // has_value + { + const std::expected e(5); + assert(e.has_value()); + } + + // !has_value + { + const std::expected e(std::unexpect, 5); + assert(!e.has_value()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/value.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/value.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/value.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const T& value() const &; +// constexpr T& value() &; +// constexpr T&& value() &&; +// constexpr const T&& value() const &&; + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +constexpr bool test() { + // non-const & + { + std::expected e(5); + decltype(auto) x = e.value(); + static_assert(std::same_as); + assert(&x == &(*e)); + assert(x == 5); + } + + // const & + { + const std::expected e(5); + decltype(auto) x = e.value(); + static_assert(std::same_as); + assert(&x == &(*e)); + assert(x == 5); + } + + // non-const && + { + std::expected e(5); + decltype(auto) x = std::move(e).value(); + static_assert(std::same_as); + assert(&x == &(*e)); + assert(x == 5); + } + + // const && + { + const std::expected e(5); + decltype(auto) x = std::move(e).value(); + static_assert(std::same_as); + assert(&x == &(*e)); + assert(x == 5); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + + // int + { + const std::expected e(std::unexpect, 5); + try { + e.value(); + assert(false); + } catch (const std::bad_expected_access& ex) { + assert(ex.error() == 5); + } + } + + // MoveOnly + { + std::expected e(std::unexpect, 5); + try { + std::move(e).value(); + assert(false); + } catch (const std::bad_expected_access& ex) { + assert(ex.error() == 5); + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/value_or.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/value_or.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/value_or.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template constexpr T value_or(U&& v) const &; +// template constexpr T value_or(U&& v) &&; + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +constexpr bool test() { + // const &, has_value() + { + const std::expected e(5); + std::same_as decltype(auto) x = e.value_or(10); + assert(x == 5); + } + + // const &, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = e.value_or(10); + assert(x == 10); + } + + // &&, has_value() + { + std::expected e(std::in_place, 5); + std::same_as decltype(auto) x = std::move(e).value_or(10); + assert(x == 5); + } + + // &&, !has_value() + { + std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = std::move(e).value_or(10); + assert(x == 10); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + + // int + { + const std::expected e(std::unexpect, 5); + try { + e.value(); + assert(false); + } catch (const std::bad_expected_access& ex) { + assert(ex.error() == 5); + } + } + + // MoveOnly + { + std::expected e(std::unexpect, 5); + try { + std::move(e).value(); + assert(false); + } catch (const std::bad_expected_access& ex) { + assert(ex.error() == 5); + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/swap/free.swap.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/swap/free.swap.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/swap/free.swap.pass.cpp @@ -0,0 +1,201 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); + +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow&&) noexcept(false); + friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {} +}; + +// Test noexcept +template +concept FreeSwapNoexcept = + requires(std::expected x, std::expected y) { + { swap(x, y) } noexcept; + }; + +static_assert(FreeSwapNoexcept); + +// !is_nothrow_move_constructible_v +static_assert(!FreeSwapNoexcept); + +// !is_nothrow_move_constructible_v +static_assert(!FreeSwapNoexcept); + +struct SwapMayThrow { + friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {} +}; + +// !is_nothrow_swappable_v +static_assert(!FreeSwapNoexcept); + +// !is_nothrow_swappable_v +static_assert(!FreeSwapNoexcept); + +constexpr bool test() { + // this->has_value() && rhs.has_value() + { + std::expected x(std::in_place, 5); + std::expected y(std::in_place, 10); + swap(x, y); + + assert(x.has_value()); + assert(x->i == 10); + assert(x->adlSwapCalled); + assert(y.has_value()); + assert(y->i == 5); + assert(y->adlSwapCalled); + } + + // !this->has_value() && !rhs.has_value() + { + std::expected x(std::unexpect, 5); + std::expected y(std::unexpect, 10); + swap(x, y); + + assert(!x.has_value()); + assert(x.error().i == 10); + assert(x.error().adlSwapCalled); + assert(!y.has_value()); + assert(y.error().i == 5); + assert(y.error().adlSwapCalled); + } + + // this->has_value() && !rhs.has_value() + // && is_nothrow_move_constructible_v + { + std::expected, TrackedMove> e1(std::in_place, 5); + std::expected, TrackedMove> e2(std::unexpect, 10); + + swap(e1, e2); + + assert(!e1.has_value()); + assert(e1.error().i == 10); + assert(e2.has_value()); + assert(e2->i == 5); + + assert(e1.error().numberOfMoves == 2); + assert(!e1.error().swapCalled); + assert(e2->numberOfMoves == 1); + assert(!e2->swapCalled); + } + + // this->has_value() && !rhs.has_value() + // && !is_nothrow_move_constructible_v + { + std::expected, TrackedMove> e1(std::in_place, 5); + std::expected, TrackedMove> e2(std::unexpect, 10); + + e1.swap(e2); + + assert(!e1.has_value()); + assert(e1.error().i == 10); + assert(e2.has_value()); + assert(e2->i == 5); + + assert(e1.error().numberOfMoves == 1); + assert(!e1.error().swapCalled); + assert(e2->numberOfMoves == 2); + assert(!e2->swapCalled); + } + + // !this->has_value() && rhs.has_value() + // && is_nothrow_move_constructible_v + { + std::expected, TrackedMove> e1(std::unexpect, 10); + std::expected, TrackedMove> e2(std::in_place, 5); + + swap(e1, e2); + + assert(e1.has_value()); + assert(e1->i == 5); + assert(!e2.has_value()); + assert(e2.error().i == 10); + + assert(e1->numberOfMoves == 1); + assert(!e1->swapCalled); + assert(e2.error().numberOfMoves == 2); + assert(!e2.error().swapCalled); + } + + // !this->has_value() && rhs.has_value() + // && !is_nothrow_move_constructible_v + { + std::expected, TrackedMove> e1(std::unexpect, 10); + std::expected, TrackedMove> e2(std::in_place, 5); + + swap(e1, e2); + + assert(e1.has_value()); + assert(e1->i == 5); + assert(!e2.has_value()); + assert(e2.error().i == 10); + + assert(e1->numberOfMoves == 2); + assert(!e1->swapCalled); + assert(e2.error().numberOfMoves == 1); + assert(!e2.error().swapCalled); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowOnMove { + ThrowOnMove() = default; + ThrowOnMove(ThrowOnMove&&) { throw Except{}; }; + ThrowOnMove& operator=(ThrowOnMove&&) = default; + }; + + // !e1.has_value() && e2.has_value() + { + std::expected e1(std::unexpect, 5); + std::expected e2(std::in_place); + try { + swap(e1, e2); + assert(false); + } catch (Except) { + assert(!e1.has_value()); + assert(e1.error() == 5); + } + } + + // e1.has_value() && !e2.has_value() + { + std::expected e1(5); + std::expected e2(std::unexpect); + try { + swap(e1, e2); + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(*e1 == 5); + } + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp @@ -0,0 +1,247 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr void swap(expected& rhs) noexcept(see below); +// +// Constraints: +// is_swappable_v is true and +// is_swappable_v is true and +// is_move_constructible_v && is_move_constructible_v is true, and +// is_nothrow_move_constructible_v || is_nothrow_move_constructible_v is true. +// +// Throws: Any exception thrown by the expressions in the Effects. +// Remarks: The exception specification is equivalent to: +// is_nothrow_move_constructible_v && is_nothrow_swappable_v && +// is_nothrow_move_constructible_v && is_nothrow_swappable_v + +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +// Test Constraints: +template +concept HasMemberSwap = requires(std::expected x, std::expected y) { x.swap(y); }; + +static_assert(HasMemberSwap); + +struct NotSwappable {}; +void swap(NotSwappable&, NotSwappable&) = delete; + +// !is_swappable_v +static_assert(!HasMemberSwap); + +// !is_swappable_v +static_assert(!HasMemberSwap); + +struct NotMoveContructible { + NotMoveContructible(NotMoveContructible&&) = delete; + friend void swap(NotMoveContructible&, NotMoveContructible&) {} +}; + +// !is_move_constructible_v +static_assert(!HasMemberSwap); + +// !is_move_constructible_v +static_assert(!HasMemberSwap); + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow&&) noexcept(false); + friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {} +}; + +// !is_nothrow_move_constructible_v && is_nothrow_move_constructible_v +static_assert(HasMemberSwap); + +// is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v +static_assert(HasMemberSwap); + +// !is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v +static_assert(!HasMemberSwap); + +// Test noexcept +template +concept MemberSwapNoexcept = + requires(std::expected x, std::expected y) { + { x.swap(y) } noexcept; + }; + +static_assert(MemberSwapNoexcept); + +// !is_nothrow_move_constructible_v +static_assert(!MemberSwapNoexcept); + +// !is_nothrow_move_constructible_v +static_assert(!MemberSwapNoexcept); + +struct SwapMayThrow { + friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {} +}; + +// !is_nothrow_swappable_v +static_assert(!MemberSwapNoexcept); + +// !is_nothrow_swappable_v +static_assert(!MemberSwapNoexcept); + +constexpr bool test() { + // this->has_value() && rhs.has_value() + { + std::expected x(std::in_place, 5); + std::expected y(std::in_place, 10); + x.swap(y); + + assert(x.has_value()); + assert(x->i == 10); + assert(x->adlSwapCalled); + assert(y.has_value()); + assert(y->i == 5); + assert(y->adlSwapCalled); + } + + // !this->has_value() && !rhs.has_value() + { + std::expected x(std::unexpect, 5); + std::expected y(std::unexpect, 10); + x.swap(y); + + assert(!x.has_value()); + assert(x.error().i == 10); + assert(x.error().adlSwapCalled); + assert(!y.has_value()); + assert(y.error().i == 5); + assert(y.error().adlSwapCalled); + } + + // this->has_value() && !rhs.has_value() + // && is_nothrow_move_constructible_v + { + std::expected, TrackedMove> e1(std::in_place, 5); + std::expected, TrackedMove> e2(std::unexpect, 10); + + e1.swap(e2); + + assert(!e1.has_value()); + assert(e1.error().i == 10); + assert(e2.has_value()); + assert(e2->i == 5); + + assert(e1.error().numberOfMoves == 2); + assert(!e1.error().swapCalled); + assert(e2->numberOfMoves == 1); + assert(!e2->swapCalled); + } + + // this->has_value() && !rhs.has_value() + // && !is_nothrow_move_constructible_v + { + std::expected, TrackedMove> e1(std::in_place, 5); + std::expected, TrackedMove> e2(std::unexpect, 10); + + e1.swap(e2); + + assert(!e1.has_value()); + assert(e1.error().i == 10); + assert(e2.has_value()); + assert(e2->i == 5); + + assert(e1.error().numberOfMoves == 1); + assert(!e1.error().swapCalled); + assert(e2->numberOfMoves == 2); + assert(!e2->swapCalled); + } + + // !this->has_value() && rhs.has_value() + // && is_nothrow_move_constructible_v + { + std::expected, TrackedMove> e1(std::unexpect, 10); + std::expected, TrackedMove> e2(std::in_place, 5); + + e1.swap(e2); + + assert(e1.has_value()); + assert(e1->i == 5); + assert(!e2.has_value()); + assert(e2.error().i == 10); + + assert(e1->numberOfMoves == 1); + assert(!e1->swapCalled); + assert(e2.error().numberOfMoves == 2); + assert(!e2.error().swapCalled); + } + + // !this->has_value() && rhs.has_value() + // && !is_nothrow_move_constructible_v + { + std::expected, TrackedMove> e1(std::unexpect, 10); + std::expected, TrackedMove> e2(std::in_place, 5); + + e1.swap(e2); + + assert(e1.has_value()); + assert(e1->i == 5); + assert(!e2.has_value()); + assert(e2.error().i == 10); + + assert(e1->numberOfMoves == 2); + assert(!e1->swapCalled); + assert(e2.error().numberOfMoves == 1); + assert(!e2.error().swapCalled); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowOnMove { + ThrowOnMove() = default; + ThrowOnMove(ThrowOnMove&&) { throw Except{}; }; + ThrowOnMove& operator=(ThrowOnMove&&) = default; + }; + + // !e1.has_value() && e2.has_value() + { + std::expected e1(std::unexpect, 5); + std::expected e2(std::in_place); + try { + e1.swap(e2); + assert(false); + } catch (Except) { + assert(!e1.has_value()); + assert(e1.error() == 5); + } + } + + // e1.has_value() && !e2.has_value() + { + std::expected e1(5); + std::expected e2(std::unexpect); + try { + e1.swap(e2); + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(*e1 == 5); + } + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/assign/assign.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/assign/assign.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/assign/assign.copy.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr unexpected& operator=(const unexpected&) = default; + +#include +#include + +struct Error { + int i; + constexpr Error(int ii) : i(ii) {} +}; + +constexpr bool test() { + std::unexpected unex1(4); + const std::unexpected unex2(5); + unex1 = unex2; + assert(unex1.error().i == 5); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/assign/assign.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/assign/assign.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/assign/assign.move.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr unexpected& operator=(unexpected&&) = default; + +#include +#include +#include + +struct Error { + int i; + constexpr Error(int ii) : i(ii) {} + constexpr Error& operator=(Error&& other) { + i = other.i; + other.i = 0; + return *this; + } +}; + +constexpr bool test() { + std::unexpected unex1(4); + std::unexpected unex2(5); + unex1 = std::move(unex2); + assert(unex1.error().i == 5); + assert(unex2.error().i == 0); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/array.compile.fail.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/array.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/array.compile.fail.cpp @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// A program that instantiates the definition of unexpected for an array type is ill-formed. + +#include + +template class std::unexpected; diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/const.compile.fail.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/const.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/const.compile.fail.cpp @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// A program that instantiates the definition of unexpected for a cv-qualified type is ill-formed. + +#include + +template class std::unexpected; diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/non_object.compile.fail.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/non_object.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/non_object.compile.fail.cpp @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// A program that instantiates the definition of unexpected for a non-object type is ill-formed. + +#include + +template class std::unexpected; diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/unexpected.compile.fail.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/unexpected.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/unexpected.compile.fail.cpp @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// A program that instantiates the definition of unexpected for a specialization of unexpected is ill-formed. + +#include + +template class std::unexpected>; diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/volatile.compile.fail.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/volatile.compile.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/class_mandates/volatile.compile.fail.cpp @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// A program that instantiates the definition of unexpected for a cv-qualified type is ill-formed. + +#include + +template class std::unexpected; diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/ctad.compile.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/ctad.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/ctad.compile.pass.cpp @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template unexpected(E) -> unexpected; + +#include +#include + +struct Foo{}; + +static_assert(std::same_as>); +static_assert(std::same_as>); +static_assert(std::same_as(5))), std::unexpected>); diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.copy.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr unexpected(const unexpected&) = default; + +#include +#include + +struct Error { + int i; + constexpr Error(int ii) : i(ii) {} +}; + +constexpr bool test() { + const std::unexpected unex(5); + auto unex2 = unex; + assert(unex2.error().i == 5); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.error.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.error.pass.cpp @@ -0,0 +1,122 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit unexpected(Err&& e); +// +// Constraints: +// - is_same_v, unexpected> is false; and +// - is_same_v, in_place_t> is false; and +// - is_constructible_v is true. +// +// Effects: Direct-non-list-initializes unex with std::forward(e). +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include + +#include "test_macros.h" + +// Test Constraints: +static_assert(std::constructible_from, int>); + +// is_same_v, unexpected> +struct CstrFromUnexpected { + CstrFromUnexpected(CstrFromUnexpected const&) = delete; + CstrFromUnexpected(std::unexpected const&); +}; +static_assert(!std::constructible_from, std::unexpected>); + +// is_same_v, in_place_t> +struct CstrFromInplace { + CstrFromInplace(std::in_place_t); +}; +static_assert(!std::constructible_from, std::in_place_t>); + +// !is_constructible_v +struct Foo {}; +static_assert(!std::constructible_from, int>); + +// test explicit +static_assert(std::convertible_to); +static_assert(!std::convertible_to>); + +struct Error { + int i; + constexpr Error(int ii) : i(ii) {} + constexpr Error(const Error& other) : i(other.i) {} + constexpr Error(Error&& other) : i(other.i) { other.i = 0; } + Error(std::initializer_list) { assert(false); } +}; + +constexpr bool test() { + // lvalue + { + Error e(5); + std::unexpected unex(e); + assert(unex.error().i == 5); + assert(e.i == 5); + } + + // rvalue + { + Error e(5); + std::unexpected unex(std::move(e)); + assert(unex.error().i == 5); + assert(e.i == 0); + } + + // Direct-non-list-initializes: does not trigger initializer_list overload + { + Error e(5); + [[maybe_unused]] std::unexpected unex(e); + } + + // Test default template argument. + // Without it, the template parameter cannot be deduced from an initializer list + { + struct Bar { + int i; + int j; + constexpr Bar(int ii, int jj) : i(ii), j(jj) {} + }; + std::unexpected ue({5, 6}); + assert(ue.error().i == 5); + assert(ue.error().j == 6); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing() = default; + Throwing(const Throwing&) { throw Except{}; } + }; + + Throwing t; + try { + std::unexpected u(t); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.inplace.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.inplace.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.inplace.pass.cpp @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit unexpected(in_place_t, Args&&... args); +// +// Constraints: is_constructible_v is true. +// +// Effects: Direct-non-list-initializes unex with std::forward(args).... +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include + +#include "test_macros.h" + +// Test Constraints: +static_assert(std::constructible_from, std::in_place_t, int>); + +// !is_constructible_v +struct Foo {}; +static_assert(!std::constructible_from, std::in_place_t, int>); + +// test explicit +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +static_assert(ImplicitlyConstructible); +static_assert(!ImplicitlyConstructible, std::in_place_t, int>); + +struct Arg { + int i; + constexpr Arg(int ii) : i(ii) {} + constexpr Arg(const Arg& other) : i(other.i) {} + constexpr Arg(Arg&& other) : i(other.i) { other.i = 0; } +}; + +struct Error { + Arg arg; + constexpr explicit Error(const Arg& a) : arg(a) {} + constexpr explicit Error(Arg&& a) : arg(std::move(a)) {} + Error(std::initializer_list) :arg(0){ assert(false); } +}; + +constexpr bool test() { + // lvalue + { + Arg a{5}; + std::unexpected unex(std::in_place, a); + assert(unex.error().arg.i == 5); + assert(a.i == 5); + } + + // rvalue + { + Arg a{5}; + std::unexpected unex(std::in_place, std::move(a)); + assert(unex.error().arg.i == 5); + assert(a.i == 0); + } + + // Direct-non-list-initializes: does not trigger initializer_list overload + { + Error e(5); + [[maybe_unused]] std::unexpected unex(std::in_place, e); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; } + }; + + try { + std::unexpected u(std::in_place, 5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.inplace_init_list.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.inplace_init_list.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.inplace_init_list.pass.cpp @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit unexpected(in_place_t, initializer_list il, Args&&... args); +// +// Constraints: is_constructible_v&, Args...> is true. +// +// Effects: Direct-non-list-initializes unex with il, std::forward(args).... +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +struct Arg { + int i; + constexpr Arg(int ii) : i(ii) {} + constexpr Arg(const Arg& other) : i(other.i) {} + constexpr Arg(Arg&& other) : i(other.i) { other.i = 0; } +}; + +struct Error { + std::initializer_list list; + Arg arg; + constexpr explicit Error(std::initializer_list l, const Arg& a) : list(l), arg(a) {} + constexpr explicit Error(std::initializer_list l, Arg&& a) : list(l), arg(std::move(a)) {} +}; + +// Test Constraints: +static_assert(std::constructible_from, std::in_place_t, std::initializer_list, Arg>); + +// !is_constructible_v&, Args...> +struct Foo {}; +static_assert(!std::constructible_from, std::in_place_t, std::initializer_list, Arg>); + +// test explicit +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +static_assert(ImplicitlyConstructible); +static_assert(!ImplicitlyConstructible, std::in_place_t, std::initializer_list, Arg>); + +constexpr bool test() { + // lvalue + { + Arg a{5}; + auto l = {1, 2, 3}; + std::unexpected unex(std::in_place, l, a); + assert(unex.error().arg.i == 5); + assert(std::ranges::equal(unex.error().list, l)); + assert(a.i == 5); + } + + // rvalue + { + Arg a{5}; + auto l = {1, 2, 3}; + std::unexpected unex(std::in_place, l, std::move(a)); + assert(unex.error().arg.i == 5); + assert(std::ranges::equal(unex.error().list, l)); + assert(a.i == 0); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(std::initializer_list, int) { throw Except{}; } + }; + + try { + std::unexpected u(std::in_place, {1, 2}, 5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.move.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr unexpected(unexpected&&) = default; + +#include +#include +#include + +struct Error { + int i; + constexpr Error(int ii) : i(ii) {} + constexpr Error(Error&& other) : i(other.i) {other.i = 0;} +}; + +constexpr bool test() { + std::unexpected unex(5); + auto unex2 = std::move(unex); + assert(unex2.error().i == 5); + assert(unex.error().i == 0); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/equality.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/equality.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/equality.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// friend constexpr bool operator==(const unexpected& x, const unexpected& y); +// +// Mandates: The expression x.error() == y.error() is well-formed and its result is convertible to bool. +// +// Returns: x.error() == y.error(). + +#include +#include +#include +#include + +struct Error{ + int i; + friend constexpr bool operator==(const Error&, const Error&) = default; +}; + +constexpr bool test() { + std::unexpected unex1(Error{2}); + std::unexpected unex2(Error{3}); + std::unexpected unex3(Error{2}); + assert(unex1 == unex3); + assert(unex1 != unex2); + assert(unex2 != unex3); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.const_ref.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.const_ref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.const_ref.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const E& error() const & noexcept; + +#include +#include +#include +#include + +template +concept ErrorNoexcept = + requires(const T& t) { + { t.error() } noexcept; + }; + +static_assert(!ErrorNoexcept); +static_assert(ErrorNoexcept>); + +constexpr bool test() { + const std::unexpected unex(5); + decltype(auto) i = unex.error(); + static_assert(std::same_as); + assert(i == 5); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.const_ref_ref.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.const_ref_ref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.const_ref_ref.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const E&& error() const && noexcept; + +#include +#include +#include +#include + +template +concept ErrorNoexcept = + requires(const T&& t) { + { std::move(t).error() } noexcept; + }; + +static_assert(!ErrorNoexcept); +static_assert(ErrorNoexcept>); + +constexpr bool test() { + const std::unexpected unex(5); + decltype(auto) i = std::move(unex).error(); + static_assert(std::same_as); + assert(i == 5); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.ref.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.ref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.ref.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr E& error() & noexcept; + +#include +#include +#include +#include + +template +concept ErrorNoexcept = + requires(T& t) { + { t.error() } noexcept; + }; + +static_assert(!ErrorNoexcept); +static_assert(ErrorNoexcept>); + +constexpr bool test() { + std::unexpected unex(5); + decltype(auto) i = unex.error(); + static_assert(std::same_as); + assert(i == 5); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.ref_ref.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.ref_ref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/observer/error.ref_ref.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr E&& error() && noexcept; + +#include +#include +#include +#include + +template +concept ErrorNoexcept = + requires(T&& t) { + { std::move(t).error() } noexcept; + }; + +static_assert(!ErrorNoexcept); +static_assert(ErrorNoexcept>); + +constexpr bool test() { + std::unexpected unex(5); + decltype(auto) i = std::move(unex).error(); + static_assert(std::same_as); + assert(i == 5); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/swap/swap.free.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/swap/swap.free.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/swap/swap.free.pass.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y))); +// +// Constraints: is_swappable_v is true. +// +// Effects: Equivalent to x.swap(y). + +#include +#include +#include +#include + +// test noexcept +struct NoexceptSwap { + friend void swap(NoexceptSwap&, NoexceptSwap&) noexcept; +}; + +struct MayThrowSwap { + friend void swap(MayThrowSwap&, MayThrowSwap&); +}; + +template +concept ADLSwapNoexcept = + requires(T& t1, T& t2) { + { swap(t1, t2) } noexcept; + }; + +static_assert(ADLSwapNoexcept>); +static_assert(!ADLSwapNoexcept>); + +// test constraint +struct NonSwappable { + NonSwappable& operator=(const NonSwappable&) = delete; +}; + +static_assert(std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(!std::is_swappable_v>); + +struct ADLSwap { + constexpr ADLSwap(int ii) : i(ii) {} + ADLSwap& operator=(const ADLSwap&) = delete; + int i; + constexpr friend void swap(ADLSwap& x, ADLSwap& y) { std::swap(x.i, y.i); } +}; + +constexpr bool test() { + std::unexpected unex1(5); + std::unexpected unex2(6); + swap(unex1, unex2); + assert(unex1.error().i == 6); + assert(unex2.error().i == 5); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/swap/swap.member.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/swap/swap.member.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/swap/swap.member.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr void swap(unexpected& other) noexcept(is_nothrow_swappable_v); +// +// Mandates: is_swappable_v is true. +// +// Effects: Equivalent to: using std::swap; swap(unex, other.unex); + +#include +#include +#include +#include + +// test noexcept +struct NoexceptSwap { + friend void swap(NoexceptSwap&, NoexceptSwap&) noexcept; +}; + +struct MayThrowSwap { + friend void swap(MayThrowSwap&, MayThrowSwap&); +}; + +template +concept MemberSwapNoexcept = + requires(T& t1, T& t2) { + { t1.swap(t2) } noexcept; + }; + +static_assert(MemberSwapNoexcept>); +static_assert(!MemberSwapNoexcept>); + +struct ADLSwap { + constexpr ADLSwap(int ii) : i(ii) {} + ADLSwap& operator=(const ADLSwap&) = delete; + int i; + constexpr friend void swap(ADLSwap& x, ADLSwap& y) { std::swap(x.i, y.i); } +}; + +constexpr bool test() { + // using std::swap; + { + std::unexpected unex1(5); + std::unexpected unex2(6); + unex1.swap(unex2); + assert(unex1.error() == 6); + assert(unex2.error() == 5); + } + + // adl swap + { + std::unexpected unex1(5); + std::unexpected unex2(6); + unex1.swap(unex2); + assert(unex1.error().i == 6); + assert(unex2.error().i == 5); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected& operator=(const expected& rhs); +// +// Effects: +// - If this->has_value() && rhs.has_value() is true, no effects. +// - Otherwise, if this->has_value() is true, equivalent to: construct_at(addressof(unex), rhs.unex); has_val = false; +// - Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true. +// - Otherwise, equivalent to unex = rhs.error(). +// +// Returns: *this. +// +// Remarks: This operator is defined as deleted unless is_copy_assignable_v is true and is_copy_constructible_v is true. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotCopyConstructible { + NotCopyConstructible(const NotCopyConstructible&) = delete; + NotCopyConstructible& operator=(const NotCopyConstructible&) = default; +}; + +struct NotCopyAssignable { + NotCopyAssignable(const NotCopyAssignable&) = default; + NotCopyAssignable& operator=(const NotCopyAssignable&) = delete; +}; + +// Test constraints +static_assert(std::is_copy_assignable_v>); + +// !is_copy_assignable_v +static_assert(!std::is_copy_assignable_v>); + +// !is_copy_constructible_v +static_assert(!std::is_copy_assignable_v>); + +constexpr bool test() { + // If this->has_value() && rhs.has_value() is true, no effects. + { + std::expected e1; + std::expected e2; + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + assert(e1.has_value()); + } + + // Otherwise, if this->has_value() is true, equivalent to: construct_at(addressof(unex), rhs.unex); has_val = false; + { + Traced::state state{}; + std::expected e1; + std::expected e2(std::unexpect, state, 5); + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + assert(!e1.has_value()); + assert(e1.error().data_ == 5); + + assert(state.copyCtorCalled); + } + + // Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true. + { + Traced::state state{}; + std::expected e1(std::unexpect, state, 5); + std::expected e2; + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + assert(e1.has_value()); + + assert(state.dtorCalled); + } + + // Otherwise, equivalent to unex = rhs.error(). + { + Traced::state state{}; + std::expected e1(std::unexpect, state, 5); + std::expected e2(std::unexpect, state, 10); + decltype(auto) x = (e1 = e2); + static_assert(std::same_as&>); + assert(&x == &e1); + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + + assert(state.copyAssignCalled); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/assign.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/assign.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/assign/assign.move.pass.cpp @@ -0,0 +1,135 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected& operator=(expected&& rhs) noexcept(see below); +// +// Effects: +// - If this->has_value() && rhs.has_value() is true, no effects. +// - Otherwise, if this->has_value() is true, equivalent to: +// construct_at(addressof(unex), std::move(rhs.unex)); +// has_val = false; +// - Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true. +// - Otherwise, equivalent to unex = std::move(rhs.error()). +// +// Returns: *this. +// +// Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v && is_nothrow_move_assignable_v. +// +// This operator is defined as deleted unless is_move_constructible_v is true and is_move_assignable_v is true. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotMoveConstructible { + NotMoveConstructible(NotMoveConstructible&&) = delete; + NotMoveConstructible& operator=(NotMoveConstructible&&) = default; +}; + +struct NotMoveAssignable { + NotMoveAssignable(NotMoveAssignable&&) = default; + NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; +}; + +// Test constraints +static_assert(std::is_move_assignable_v>); + +// !is_move_assignable_v +static_assert(!std::is_move_assignable_v>); + +// !is_move_constructible_v +static_assert(!std::is_move_assignable_v>); + +// Test noexcept +struct MoveCtorMayThrow { + MoveCtorMayThrow(MoveCtorMayThrow&&) noexcept(false) {} + MoveCtorMayThrow& operator=(MoveCtorMayThrow&&) noexcept = default; +}; + +struct MoveAssignMayThrow { + MoveAssignMayThrow(MoveAssignMayThrow&&) noexcept = default; + MoveAssignMayThrow& operator=(MoveAssignMayThrow&&) noexcept(false) { return *this; } +}; + +// Test noexcept +static_assert(std::is_nothrow_move_assignable_v>); + +// !is_nothrow_move_assignable_v +static_assert(!std::is_nothrow_move_assignable_v>); + +// !is_nothrow_move_constructible_v +static_assert(!std::is_nothrow_move_assignable_v>); + +constexpr bool test() { + // If this->has_value() && rhs.has_value() is true, no effects. + { + std::expected e1; + std::expected e2; + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + assert(e1.has_value()); + } + + // Otherwise, if this->has_value() is true, equivalent to: + // construct_at(addressof(unex), std::move(rhs.unex)); + // has_val = false; + { + Traced::state state{}; + std::expected e1; + std::expected e2(std::unexpect, state, 5); + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + assert(!e1.has_value()); + assert(e1.error().data_ == 5); + + assert(state.moveCtorCalled); + } + + // Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true. + { + Traced::state state{}; + std::expected e1(std::unexpect, state, 5); + std::expected e2; + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + assert(e1.has_value()); + + assert(state.dtorCalled); + } + + // Otherwise, equivalent to unex = rhs.error(). + { + Traced::state state{}; + std::expected e1(std::unexpect, state, 5); + std::expected e2(std::unexpect, state, 10); + decltype(auto) x = (e1 = std::move(e2)); + static_assert(std::same_as&>); + assert(&x == &e1); + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + + assert(state.moveAssignCalled); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.copy.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr expected& operator=(const unexpected& e); +// +// Let GF be const G& +// +// Constraints: is_constructible_v is true and is_assignable_v is true. +// +// Effects: +// - If has_value() is true, equivalent to: +// construct_at(addressof(unex), std::forward(e.error())); +// has_val = false; +// - Otherwise, equivalent to: unex = std::forward(e.error()); +// +// Returns: *this. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotCopyConstructible { + NotCopyConstructible(const NotCopyConstructible&) = delete; + NotCopyConstructible& operator=(const NotCopyConstructible&) = default; +}; + +struct NotCopyAssignable { + NotCopyAssignable(const NotCopyAssignable&) = default; + NotCopyAssignable& operator=(const NotCopyAssignable&) = delete; +}; + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow const&) = default; + MoveMayThrow& operator=(const MoveMayThrow&) = default; + MoveMayThrow(MoveMayThrow&&) noexcept(false) {} + MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; } +}; + +// Test constraints +static_assert(std::is_assignable_v&, const std::unexpected&>); + +// !is_constructible_v +static_assert( + !std::is_assignable_v&, const std::unexpected&>); + +// !is_assignable_v +static_assert( + !std::is_assignable_v&, const std::unexpected&>); + +constexpr bool test() { + // - If has_value() is true, equivalent to: + // construct_at(addressof(unex), std::forward(e.error())); + // has_val = false; + { + Traced::state state{}; + std::expected e; + std::unexpected un(std::in_place, state, 5); + decltype(auto) x = (e = un); + static_assert(std::same_as&>); + assert(&x == &e); + assert(!e.has_value()); + assert(e.error().data_ == 5); + + assert(state.copyCtorCalled); + } + + // - Otherwise, equivalent to: unex = std::forward(e.error()); + { + Traced::state state1{}; + Traced::state state2{}; + std::expected e(std::unexpect, state1, 5); + std::unexpected un(std::in_place, state2, 10); + decltype(auto) x = (e = un); + static_assert(std::same_as&>); + assert(&x == &e); + assert(!e.has_value()); + assert(e.error().data_ == 10); + + assert(state1.copyAssignCalled); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.move.pass.cpp @@ -0,0 +1,209 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr expected& operator=(unexpected&& e); +// +// Let GF be G +// Constraints: +// - is_constructible_v is true; and +// - is_assignable_v is true; and +// - is_nothrow_constructible_v || is_nothrow_move_constructible_v || +// is_nothrow_move_constructible_v is true. +// +// Effects: +// - If has_value() is true, equivalent to: +// reinit-expected(unex, val, std::forward(e.error())); +// has_val = false; +// - Otherwise, equivalent to: unex = std::forward(e.error()); +// Returns: *this. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct NotMoveConstructible { + NotMoveConstructible(NotMoveConstructible&&) = delete; + NotMoveConstructible& operator=(NotMoveConstructible&&) = default; +}; + +struct NotMoveAssignable { + NotMoveAssignable(NotMoveAssignable&&) = default; + NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; +}; + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow const&) = default; + MoveMayThrow& operator=(const MoveMayThrow&) = default; + MoveMayThrow(MoveMayThrow&&) noexcept(false) {} + MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; } +}; + +// Test constraints +static_assert(std::is_assignable_v&, std::unexpected&&>); + +// !is_constructible_v +static_assert( + !std::is_assignable_v&, std::unexpected&&>); + +// !is_assignable_v +static_assert(!std::is_assignable_v&, std::unexpected&&>); + +template +struct MaybeNoexcept { + explicit MaybeNoexcept(int) noexcept(convertNoexcept); + MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept); + MaybeNoexcept& operator=(MaybeNoexcept&&) = default; + MaybeNoexcept& operator=(int); +}; + +// !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + std::unexpected&&>); + +// is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + std::unexpected&&>); + +// !is_nothrow_constructible_v && is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(std::is_assignable_v, MaybeNoexcept>&, + std::unexpected&&>); + +// !is_nothrow_constructible_v && !is_nothrow_move_constructible_v && +// !is_nothrow_move_constructible_v +static_assert(!std::is_assignable_v, MaybeNoexcept>&, + std::unexpected&&>); + +constexpr bool test() { + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // is_nothrow_constructible_v + // + // In this case, it should call the branch + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::forward(args)...); + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + std::unexpected un(10); + decltype(auto) x = (e = std::move(un)); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e.error().movedFromInt); + } + + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // !is_nothrow_constructible_v && is_nothrow_move_constructible_v + // + // In this case, it should call the branch + // T tmp(std::forward(args)...); + // destroy_at(addressof(oldval)); + // construct_at(addressof(newval), std::move(tmp)); + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + std::unexpected un(10); + decltype(auto) x = (e = std::move(un)); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(!oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(!e.error().movedFromInt); + assert(e.error().movedFromTmp); + } + + // - If has_value() is true, equivalent to: + // reinit-expected(unex, val, std::forward(e.error())); + // !is_nothrow_constructible_v && !is_nothrow_move_constructible_v + // is_nothrow_move_constructible_v + // + // In this case, it should call the branch + // U tmp(std::move(oldval)); + // destroy_at(addressof(oldval)); + // try { + // construct_at(addressof(newval), std::forward(args)...); + // } catch (...) { + // construct_at(addressof(oldval), std::move(tmp)); + // throw; + // } + { + BothNoexcept::state oldState{}; + std::expected e(std::in_place, oldState, 5); + std::unexpected un(10); + decltype(auto) x = (e = std::move(un)); + static_assert(std::same_as&>); + assert(&x == &e); + + assert(oldState.moveCtorCalled); + assert(oldState.dtorCalled); + assert(e.error().movedFromInt); + } + + // Otherwise, equivalent to: unex = std::forward(e.error()); + { + Traced::state oldState{}; + Traced::state newState{}; + std::expected e1(std::unexpect, oldState, 5); + std::unexpected e(std::in_place, newState, 10); + decltype(auto) x = (e1 = std::move(e)); + static_assert(std::same_as&>); + assert(&x == &e1); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + assert(oldState.moveAssignCalled); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowOnConvert { + ThrowOnConvert() = default; + ThrowOnConvert(const int&) {} + ThrowOnConvert(int&&) { throw Except{}; } + ThrowOnConvert(const ThrowOnConvert&) noexcept(false) {} + ThrowOnConvert& operator=(const ThrowOnConvert&) = default; + ThrowOnConvert(ThrowOnConvert&&) noexcept(false) {} + ThrowOnConvert& operator=(ThrowOnConvert&&) = default; + }; + + std::expected e1(std::in_place, 5); + std::unexpected un(10); + try { + e1 = std::move(un); + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(*e1 == 5); + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/emplace.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/emplace.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/assign/emplace.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr void emplace() noexcept; +// +// Effects: If has_value() is false, destroys unex and sets has_val to true. + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +template +concept EmplaceNoexcept = + requires(T t) { + { t.emplace() } noexcept; + }; +static_assert(!EmplaceNoexcept); + +static_assert(EmplaceNoexcept>); + +constexpr bool test() { + // has_value + { + std::expected e; + e.emplace(); + assert(e.has_value()); + } + + // !has_value + { + Traced::state state{}; + std::expected e(std::unexpect, state, 5); + e.emplace(); + + assert(state.dtorCalled); + assert(e.has_value()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.convert.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.convert.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.convert.copy.pass.cpp @@ -0,0 +1,129 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(!is_convertible_v) expected(const expected& rhs); +// +// Let GF be const G& +// +// Constraints: +// - is_void_v is true; and +// - is_constructible_v is true; and +// - is_constructible_v, expected&> is false; and +// - is_constructible_v, expected> is false; and +// - is_constructible_v, const expected&> is false; and +// - is_constructible_v, const expected> is false. +// +// Effects: If rhs.has_value() is false, direct-non-list-initializes unex with std::forward(rhs.error()). +// +// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test Constraints: +template +concept canCstrFromExpected = std::is_constructible_v, const std::expected&>; + +struct CtorFromInt { + CtorFromInt(int); +}; + +static_assert(canCstrFromExpected); + +struct NoCtorFromInt {}; + +// !is_void_v +static_assert(!canCstrFromExpected); + +// !is_constructible_v +static_assert(!canCstrFromExpected); + +template +struct CtorFrom { + explicit CtorFrom(int) + requires(!std::same_as); + explicit CtorFrom(T); + explicit CtorFrom(auto&&) = delete; +}; + +// Note for below 4 tests, because their E is constructible from cvref of std::expected, +// unexpected will be constructible from cvref of std::expected +// is_constructible_v, expected&> +static_assert(!canCstrFromExpected&>, void, int>); + +// is_constructible_v, expected> +static_assert(!canCstrFromExpected&&>, void, int>); + +// is_constructible_v, const expected&> is false +static_assert(!canCstrFromExpected const&>, void, int>); + +// is_constructible_v, const expected> +static_assert(!canCstrFromExpected const&&>, void, int>); + +// test explicit +static_assert(std::is_convertible_v&, std::expected>); + +// !is_convertible_v. +static_assert(std::is_constructible_v>, const std::expected&>); +static_assert(!std::is_convertible_v&, std::expected>>); + +struct Data { + int i; + constexpr Data(int ii) : i(ii) {} +}; + +constexpr bool test() { + // convert the error + { + const std::expected e1(std::unexpect, 5); + std::expected e2 = e1; + assert(!e2.has_value()); + assert(e2.error().i == 5); + assert(!e1.has_value()); + assert(e1.error() == 5); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowingInt { + ThrowingInt(int) { throw Except{}; } + }; + + // throw on converting error + { + const std::expected e1(std::unexpect); + try { + [[maybe_unused]] std::expected e2 = e1; + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.convert.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.convert.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.convert.move.pass.cpp @@ -0,0 +1,130 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(!is_convertible_v) expected(expected&& rhs); +// +// Let GF be G +// +// Constraints: +// - is_void_v is true; and +// - is_constructible_v is true; and +// - is_constructible_v, expected&> is false; and +// - is_constructible_v, expected> is false; and +// - is_constructible_v, const expected&> is false; and +// - is_constructible_v, const expected> is false. +// +// Effects: If rhs.has_value() is false, direct-non-list-initializes unex with std::forward(rhs.error()). +// +// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +template +concept canCstrFromExpected = std::is_constructible_v, std::expected&&>; + +struct CtorFromInt { + CtorFromInt(int); +}; + +static_assert(canCstrFromExpected); + +struct NoCtorFromInt {}; + +// !is_void_v +static_assert(!canCstrFromExpected); + +// !is_constructible_v +static_assert(!canCstrFromExpected); + +template +struct CtorFrom { + explicit CtorFrom(int) + requires(!std::same_as); + explicit CtorFrom(T); + explicit CtorFrom(auto&&) = delete; +}; + +// Note for below 4 tests, because their E is constructible from cvref of std::expected, +// unexpected will be constructible from cvref of std::expected +// is_constructible_v, expected&> +static_assert(!canCstrFromExpected&>, void, int>); + +// is_constructible_v, expected> +static_assert(!canCstrFromExpected&&>, void, int>); + +// is_constructible_v, const expected&> is false +static_assert(!canCstrFromExpected const&>, void, int>); + +// is_constructible_v, const expected> +static_assert(!canCstrFromExpected const&&>, void, int>); + +// test explicit +static_assert(std::is_convertible_v&&, std::expected>); + +// !is_convertible_v. +static_assert(std::is_constructible_v>, std::expected&&>); +static_assert(!std::is_convertible_v&&, std::expected>>); + +struct Data { + MoveOnly data; + constexpr Data(MoveOnly&& m) : data(std::move(m)) {} +}; + +constexpr bool test() { + // convert the error + { + std::expected e1(std::unexpect, 5); + std::expected e2 = std::move(e1); + assert(!e2.has_value()); + assert(e2.error().data.get() == 5); + assert(!e1.has_value()); + assert(e1.error().get() == 0); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct ThrowingInt { + ThrowingInt(int) { throw Except{}; } + }; + + // throw on converting error + { + const std::expected e1(std::unexpect); + try { + [[maybe_unused]] std::expected e2 = e1; + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.copy.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected(const expected& rhs); +// +// Effects: If rhs.has_value() is false, direct-non-list-initializes unex with rhs.error(). +// +// Postconditions: rhs.has_value() == this->has_value(). +// +// Throws: Any exception thrown by the initialization of unex. +// +// Remarks: +// - This constructor is defined as deleted unless is_copy_constructible_v is true. +// - This constructor is trivial if is_trivially_copy_constructible_v is true. + +#include +#include +#include +#include + +#include "test_macros.h" + +struct NonCopyable { + NonCopyable(const NonCopyable&) = delete; +}; + +struct CopyableNonTrivial { + int i; + constexpr CopyableNonTrivial(int ii) : i(ii) {} + constexpr CopyableNonTrivial(const CopyableNonTrivial& o) { i = o.i; } + friend constexpr bool operator==(const CopyableNonTrivial&, const CopyableNonTrivial&) = default; +}; + +// Test: This constructor is defined as deleted unless is_copy_constructible_v is true. +static_assert(std::is_copy_constructible_v>); +static_assert(std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); + +// Test: This constructor is trivial if is_trivially_copy_constructible_v is true. +#if __cpp_concepts >= 202002 +static_assert(std::is_trivially_copy_constructible_v>); +#endif +static_assert(!std::is_trivially_copy_constructible_v>); + +constexpr bool test() { + // copy the error non-trivial + { + const std::expected e1(std::unexpect, 5); + auto e2 = e1; + assert(!e2.has_value()); + assert(e2.error().i == 5); + } + + // copy the error trivial + { + const std::expected e1(std::unexpect, 5); + auto e2 = e1; + assert(!e2.has_value()); + assert(e2.error() == 5); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing() = default; + Throwing(const Throwing&) { throw Except{}; } + }; + + // throw on copying error + { + const std::expected e1(std::unexpect); + try { + [[maybe_unused]] auto e2 = e1; + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.default.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.default.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected() noexcept; + +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept + +struct NoDefaultCtor { + constexpr NoDefaultCtor() = delete; +}; + +static_assert(std::is_nothrow_default_constructible_v>); +static_assert(std::is_nothrow_default_constructible_v>); + +struct MyInt { + int i; + friend constexpr bool operator==(const MyInt&, const MyInt&) = default; +}; + +constexpr bool test() { + // default constructible + { + std::expected e; + assert(e.has_value()); + } + + // non-default constructible + { + std::expected e; + assert(e.has_value()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.inplace.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.inplace.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.inplace.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr explicit expected(in_place_t) noexcept; + +#include +#include +#include +#include + +// test explicit +static_assert(std::is_constructible_v, std::in_place_t>); +static_assert(!std::is_convertible_v>); + +// test noexcept +static_assert(std::is_nothrow_constructible_v, std::in_place_t>); + +constexpr bool test() { + std::expected e(std::in_place); + assert(e.has_value()); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.move.pass.cpp @@ -0,0 +1,111 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr expected(expected&& rhs) noexcept(is_nothrow_move_constructible_v); +// +// Constraints: is_move_constructible_v is true. +// +// Effects: If rhs.has_value() is false, direct-non-list-initializes unex with std::move(rhs.error()). +// +// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true. +// +// Throws: Any exception thrown by the initialization of unex. +// +// Remarks: This constructor is trivial if is_trivially_move_constructible_v is true. + +#include +#include +#include +#include + +#include "test_macros.h" + +struct NonMovable { + NonMovable(NonMovable&&) = delete; +}; + +struct MovableNonTrivial { + int i; + constexpr MovableNonTrivial(int ii) : i(ii) {} + constexpr MovableNonTrivial(MovableNonTrivial&& o) : i(o.i) { o.i = 0; } + friend constexpr bool operator==(const MovableNonTrivial&, const MovableNonTrivial&) = default; +}; + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow&&) {} +}; + +// Test Constraints: +// - is_move_constructible_v is true. +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); +static_assert(!std::is_move_constructible_v>); + +// Test: This constructor is trivial if is_trivially_move_constructible_v is true. +#if __cpp_concepts >= 202002 +static_assert(std::is_trivially_move_constructible_v>); +#endif +static_assert(!std::is_trivially_move_constructible_v>); + +// Test: noexcept(is_nothrow_move_constructible_v) +static_assert(std::is_nothrow_move_constructible_v>); +static_assert(!std::is_nothrow_move_constructible_v>); +static_assert(!std::is_nothrow_move_constructible_v>); +static_assert(!std::is_nothrow_move_constructible_v>); + +constexpr bool test() { + // move the error non-trivial + { + std::expected e1(std::unexpect, 5); + auto e2 = std::move(e1); + assert(!e2.has_value()); + assert(e2.error().i == 5); + assert(!e1.has_value()); + assert(e1.error().i == 0); + } + + // move the error trivial + { + std::expected e1(std::unexpect, 5); + auto e2 = std::move(e1); + assert(!e2.has_value()); + assert(e2.error() == 5); + assert(!e1.has_value()); + } + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing() = default; + Throwing(Throwing&&) { throw Except{}; } + }; + + // throw on moving error + { + std::expected e1(std::unexpect); + try { + [[maybe_unused]] auto e2 = std::move(e1); + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpect.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpect.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpect.pass.cpp @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit expected(unexpect_t, Args&&... args); +// +// Constraints: is_constructible_v is true. +// +// Effects: Direct-non-list-initializes unex with std::forward(args).... +// +// Postconditions: has_value() is false. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +static_assert(std::is_constructible_v, std::unexpect_t>); +static_assert(std::is_constructible_v, std::unexpect_t, int>); + +// !is_constructible_v +struct foo {}; +static_assert(!std::is_constructible_v, std::unexpect_t, int>); + +// test explicit +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; +static_assert(ImplicitlyConstructible); + +static_assert(!ImplicitlyConstructible, std::unexpect_t>); +static_assert(!ImplicitlyConstructible, std::unexpect_t, int>); + +struct CopyOnly { + int i; + constexpr CopyOnly(int ii) : i(ii) {} + CopyOnly(const CopyOnly&) = default; + CopyOnly(CopyOnly&&) = delete; + friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; } +}; + +template +constexpr void testInt() { + std::expected e(std::unexpect, 5); + assert(!e.has_value()); + assert(e.error() == 5); +} + +template +constexpr void testLValue() { + T t(5); + std::expected e(std::unexpect, t); + assert(!e.has_value()); + assert(e.error() == 5); +} + +template +constexpr void testRValue() { + std::expected e(std::unexpect, T(5)); + assert(!e.has_value()); + assert(e.error() == 5); +} + +constexpr bool test() { + testInt(); + testInt(); + testInt(); + testLValue(); + testLValue(); + testRValue(); + testRValue(); + + // no arg + { + std::expected e(std::unexpect); + assert(!e.has_value()); + assert(e.error() == 0); + } + + // one arg + { + std::expected e(std::unexpect, 5); + assert(!e.has_value()); + assert(e.error() == 5); + } + + // multi args + { + std::expected> e(std::unexpect, 1, 2, MoveOnly(3)); + assert(!e.has_value()); + assert((e.error() == std::tuple(1, 2, MoveOnly(3)))); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; }; + }; + + try { + std::expected u(std::unexpect, 5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpect_init_list.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpect_init_list.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpect_init_list.pass.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit expected(unexpect_t, initializer_list il, Args&&... args); +// +// Constraints: is_constructible_v&, Args...> is true. +// +// Effects: Direct-non-list-initializes unex with il, std::forward(args).... +// +// Postconditions: has_value() is false. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints: +static_assert( + std::is_constructible_v>, std::unexpect_t, std::initializer_list>); + +// !is_constructible_v&, Args...> +static_assert(!std::is_constructible_v, std::unexpect_t, std::initializer_list>); + +// test explicit +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; +static_assert(ImplicitlyConstructible); + +static_assert( + !ImplicitlyConstructible>, std::unexpect_t, std::initializer_list>); + +template +struct Data { + std::vector vec_; + std::tuple tuple_; + + template + constexpr Data(std::initializer_list il, Us&&... us) : vec_(il), tuple_(std::forward(us)...) {} +}; + +constexpr bool test() { + // no arg + { + std::expected> e(std::unexpect, {1, 2, 3}); + assert(!e.has_value()); + auto expectedList = {1, 2, 3}; + assert(std::ranges::equal(e.error().vec_, expectedList)); + } + + // one arg + { + std::expected> e(std::unexpect, {4, 5, 6}, MoveOnly(5)); + assert(!e.has_value()); + auto expectedList = {4, 5, 6}; + assert((std::ranges::equal(e.error().vec_, expectedList))); + assert(std::get<0>(e.error().tuple_) == 5); + } + + // multi args + { + int i = 5; + int j = 6; + MoveOnly m(7); + std::expected> e(std::unexpect, {1, 2}, i, std::move(j), std::move(m)); + assert(!e.has_value()); + auto expectedList = {1, 2}; + assert((std::ranges::equal(e.error().vec_, expectedList))); + assert(&std::get<0>(e.error().tuple_) == &i); + assert(&std::get<1>(e.error().tuple_) == &j); + assert(std::get<2>(e.error().tuple_) == 7); + assert(m.get() == 0); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(std::initializer_list, int) { throw Except{}; }; + }; + + try { + std::expected u(std::unexpect, {1, 2}, 5); + assert(false); + } catch (Except) { + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpected.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpected.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpected.copy.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(!is_convertible_v) expected(const unexpected& e); +// +// Let GF be const G& +// +// Constraints: is_constructible_v is true. +// +// Effects: Direct-non-list-initializes unex with std::forward(e.error()). +// +// Postconditions: has_value() is false. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints +static_assert(std::is_constructible_v, const std::unexpected&>); + +// !is_constructible_v +struct foo {}; +static_assert(!std::is_constructible_v, const std::unexpected&>); +static_assert(!std::is_constructible_v, const std::unexpected&>); + +// explicit(!is_convertible_v) +struct NotConvertible { + explicit NotConvertible(int); +}; +static_assert(std::is_convertible_v&, std::expected>); +static_assert(!std::is_convertible_v&, std::expected>); + +struct MyInt { + int i; + constexpr MyInt(int ii) : i(ii) {} + friend constexpr bool operator==(const MyInt&, const MyInt&) = default; +}; + +template +constexpr void testUnexpected() { + const std::unexpected u(5); + std::expected e(u); + assert(!e.has_value()); + assert(e.error() == 5); +} + +constexpr bool test() { + testUnexpected(); + testUnexpected(); + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; } + }; + + { + const std::unexpected u(5); + try { + [[maybe_unused]] std::expected e(u); + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpected.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpected.move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.unexpected.move.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template +// constexpr explicit(!is_convertible_v) expected(unexpected&& e); +// +// Let GF be G +// +// Constraints: is_constructible_v is true. +// +// Effects: Direct-non-list-initializes unex with std::forward(e.error()). +// +// Postconditions: has_value() is false. +// +// Throws: Any exception thrown by the initialization of unex. + +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +// Test Constraints +static_assert(std::is_constructible_v, std::unexpected>); +static_assert(std::is_constructible_v, std::unexpected>); + +// !is_constructible_v +struct foo {}; +static_assert(!std::is_constructible_v, std::unexpected>); + +// explicit(!is_convertible_v) +struct NotConvertible { + explicit NotConvertible(int); +}; +static_assert(std::is_convertible_v&&, std::expected>); +static_assert(!std::is_convertible_v&&, std::expected>); + +struct MyInt { + int i; + constexpr MyInt(int ii) : i(ii) {} + friend constexpr bool operator==(const MyInt&, const MyInt&) = default; +}; + +template +constexpr void testInt() { + std::unexpected u(5); + std::expected e(std::move(u)); + assert(!e.has_value()); + assert(e.error() == 5); +} + +constexpr void testMoveOnly() { + std::unexpected u(MoveOnly(5)); + std::expected e(std::move(u)); + assert(!e.has_value()); + assert(e.error() == 5); + assert(u.error() == 0); +} + +constexpr bool test() { + testInt(); + testInt(); + testInt(); + testMoveOnly(); + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + struct Except {}; + + struct Throwing { + Throwing(int) { throw Except{}; } + }; + + { + std::unexpected u(5); + try { + [[maybe_unused]] std::expected e(std::move(u)); + assert(false); + } catch (Except) { + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/dtor.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/dtor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/dtor.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr ~expected(); +// +// Effects: If has_value() is false, destroys unex. +// +// Remarks: If is_trivially_destructible_v is true, then this destructor is a trivial destructor. + +#include +#include +#include +#include + +#include "test_macros.h" + +// Test Remarks: If is_trivially_destructible_v is true, then this destructor is a trivial destructor. +struct NonTrivial { + ~NonTrivial() {} +}; + +#if __cpp_concepts >= 202002 +static_assert(std::is_trivially_destructible_v>); +#endif +static_assert(!std::is_trivially_destructible_v>); + +struct TrackedDestroy { + bool& destroyed; + constexpr TrackedDestroy(bool& b) : destroyed(b) {} + constexpr ~TrackedDestroy() { destroyed = true; } +}; + +constexpr bool test() { + // has value + { [[maybe_unused]] std::expected e(std::in_place); } + + // has error + { + bool errorDestroyed = false; + { [[maybe_unused]] std::expected e(std::unexpect, errorDestroyed); } + assert(errorDestroyed); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template requires (is_void_v) +// friend constexpr bool operator==(const expected& x, const expected& y); + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test constraint +template +concept CanCompare = requires(T1 t1, T2 t2) { t1 == t2; }; + +struct Foo{}; +static_assert(!CanCompare); + +static_assert(CanCompare, std::expected>); +static_assert(CanCompare, std::expected>); + +// Note this is true because other overloads in expected are unconstrained +static_assert(CanCompare, std::expected>); + +constexpr bool test() { + // x.has_value() && y.has_value() + { + const std::expected e1; + const std::expected e2; + assert(e1 == e2); + } + + // !x.has_value() && y.has_value() + { + const std::expected e1(std::unexpect, 5); + const std::expected e2; + assert(e1 != e2); + } + + // x.has_value() && !y.has_value() + { + const std::expected e1; + const std::expected e2(std::unexpect, 10); + const std::expected e3(std::unexpect, 5); + assert(e1 != e2); + assert(e1 != e3); + } + + // !x.has_value() && !y.has_value() + { + const std::expected e1(std::unexpect, 5); + const std::expected e2(std::unexpect, 10); + const std::expected e3(std::unexpect, 5); + assert(e1 != e2); + assert(e1 == e3); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/equality/equality.unexpected.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/equality/equality.unexpected.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/equality/equality.unexpected.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template friend constexpr bool operator==(const expected& x, const unexpected& e); + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +struct Data { + int i; + constexpr Data(int ii) : i(ii) {} + + friend constexpr bool operator==(const Data& data, int ii) { return data.i == ii; } +}; + +constexpr bool test() { + // x.has_value() + { + const std::expected e1; + std::unexpected un2(10); + std::unexpected un3(5); + assert(e1 != un2); + assert(e1 != un3); + } + + // !x.has_value() + { + const std::expected e1(std::unexpect, 5); + std::unexpected un2(10); + std::unexpected un3(5); + assert(e1 != un2); + assert(e1 == un3); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/bool.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/bool.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/observers/bool.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr explicit operator bool() const noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept OpBoolNoexcept = + requires(T t) { + { static_cast(t) } noexcept; + }; + +struct Foo {}; +static_assert(!OpBoolNoexcept); + +static_assert(OpBoolNoexcept>); +static_assert(OpBoolNoexcept>); + +// Test explicit +static_assert(!std::is_convertible_v, bool>); + +constexpr bool test() { + // has_value + { + const std::expected e; + assert(static_cast(e)); + } + + // !has_value + { + const std::expected e(std::unexpect, 5); + assert(!static_cast(e)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/deref.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/deref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/observers/deref.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr void operator*() const & noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept DerefNoexcept = + requires(T t) { + { std::forward(t).operator*() } noexcept; + }; + +static_assert(!DerefNoexcept); + +static_assert(DerefNoexcept>); + +constexpr bool test() { + const std::expected e; + *e; + static_assert(std::is_same_v); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/error.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/observers/error.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr const E& error() const & noexcept; +// constexpr E& error() & noexcept; +// constexpr E&& error() && noexcept; +// constexpr const E&& error() const && noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept ErrorNoexcept = + requires(T t) { + { std::forward(t).error() } noexcept; + }; + +static_assert(!ErrorNoexcept); + +static_assert(ErrorNoexcept&>); +static_assert(ErrorNoexcept&>); +static_assert(ErrorNoexcept&&>); +static_assert(ErrorNoexcept&&>); + +constexpr bool test() { + // non-const & + { + std::expected e(std::unexpect, 5); + decltype(auto) x = e.error(); + static_assert(std::same_as); + assert(x == 5); + } + + // const & + { + const std::expected e(std::unexpect, 5); + decltype(auto) x = e.error(); + static_assert(std::same_as); + assert(x == 5); + } + + // non-const && + { + std::expected e(std::unexpect, 5); + decltype(auto) x = std::move(e).error(); + static_assert(std::same_as); + assert(x == 5); + } + + // const && + { + const std::expected e(std::unexpect, 5); + decltype(auto) x = std::move(e).error(); + static_assert(std::same_as); + assert(x == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/has_value.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/has_value.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/observers/has_value.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr bool has_value() const noexcept; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Test noexcept +template +concept HasValueNoexcept = + requires(T t) { + { t.has_value() } noexcept; + }; + +struct Foo {}; +static_assert(!HasValueNoexcept); + +static_assert(HasValueNoexcept>); +static_assert(HasValueNoexcept>); + +constexpr bool test() { + // has_value + { + const std::expected e; + assert(e.has_value()); + } + + // !has_value + { + const std::expected e(std::unexpect, 5); + assert(!e.has_value()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/value.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/value.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/observers/value.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr void value() const &; +// constexpr void value() &&; + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +constexpr bool test() { + // const & + { + const std::expected e; + e.value(); + static_assert(std::is_same_v); + } + + // & + { + std::expected e; + e.value(); + static_assert(std::is_same_v); + } + + // && + { + std::expected e; + std::move(e).value(); + static_assert(std::is_same_v); + } + + // const && + { + const std::expected e; + std::move(e).value(); + static_assert(std::is_same_v); + } + + return true; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + + // int + { + const std::expected e(std::unexpect, 5); + try { + e.value(); + assert(false); + } catch (const std::bad_expected_access& ex) { + assert(ex.error() == 5); + } + } + + // MoveOnly + { + std::expected e(std::unexpect, 5); + try { + std::move(e).value(); + assert(false); + } catch (const std::bad_expected_access& ex) { + assert(ex.error() == 5); + } + } + +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/swap/free.swap.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/swap/free.swap.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/swap/free.swap.pass.cpp @@ -0,0 +1,108 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(swap(x,y))); + +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow&&) noexcept(false); + friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {} +}; + +// Test noexcept +template +concept FreeSwapNoexcept = + requires(std::expected x, std::expected y) { + { swap(x, y) } noexcept; + }; + +static_assert(FreeSwapNoexcept); + +// !is_nothrow_move_constructible_v +static_assert(!FreeSwapNoexcept); + +struct SwapMayThrow { + friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {} +}; + +// !is_nothrow_swappable_v +static_assert(!FreeSwapNoexcept); + +constexpr bool test() { + // this->has_value() && rhs.has_value() + { + std::expected x; + std::expected y; + swap(x, y); + + assert(x.has_value()); + assert(y.has_value()); + } + + // !this->has_value() && !rhs.has_value() + { + std::expected x(std::unexpect, 5); + std::expected y(std::unexpect, 10); + swap(x, y); + + assert(!x.has_value()); + assert(x.error().i == 10); + assert(x.error().adlSwapCalled); + assert(!y.has_value()); + assert(y.error().i == 5); + assert(y.error().adlSwapCalled); + } + + // this->has_value() && !rhs.has_value() + { + Traced::state s{}; + std::expected e1(std::in_place); + std::expected e2(std::unexpect, s, 10); + + e1.swap(e2); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + assert(e2.has_value()); + + assert(s.moveCtorCalled); + assert(s.dtorCalled); + } + + // !this->has_value() && rhs.has_value() + { + Traced::state s{}; + std::expected e1(std::unexpect, s, 10); + std::expected e2(std::in_place); + + e1.swap(e2); + + assert(e1.has_value()); + assert(!e2.has_value()); + assert(e2.error().data_ == 10); + + assert(s.moveCtorCalled); + assert(s.dtorCalled); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/swap/member.swap.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/swap/member.swap.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/swap/member.swap.pass.cpp @@ -0,0 +1,137 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// constexpr void swap(expected& rhs) noexcept(see below); +// +// Constraints: +// is_swappable_v is true and is_move_constructible_v is true. +// +// Throws: Any exception thrown by the expressions in the Effects. +// +// Remarks: The exception specification is equivalent to: +// is_nothrow_move_constructible_v && is_nothrow_swappable_v. + +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +// Test Constraints: +template +concept HasMemberSwap = requires(std::expected x, std::expected y) { x.swap(y); }; + +static_assert(HasMemberSwap); + +struct NotSwappable {}; +void swap(NotSwappable&, NotSwappable&) = delete; + +// !is_swappable_v +static_assert(!HasMemberSwap); + +struct NotMoveContructible { + NotMoveContructible(NotMoveContructible&&) = delete; + friend void swap(NotMoveContructible&, NotMoveContructible&) {} +}; + +// !is_move_constructible_v +static_assert(!HasMemberSwap); + +// Test noexcept +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow&&) noexcept(false); + friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {} +}; + +template +concept MemberSwapNoexcept = + requires(std::expected x, std::expected y) { + { x.swap(y) } noexcept; + }; + +static_assert(MemberSwapNoexcept); + +// !is_nothrow_move_constructible_v +static_assert(!MemberSwapNoexcept); + +struct SwapMayThrow { + friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {} +}; + +// !is_nothrow_swappable_v +static_assert(!MemberSwapNoexcept); + +constexpr bool test() { + // this->has_value() && rhs.has_value() + { + std::expected x; + std::expected y; + x.swap(y); + + assert(x.has_value()); + assert(y.has_value()); + } + + // !this->has_value() && !rhs.has_value() + { + std::expected x(std::unexpect, 5); + std::expected y(std::unexpect, 10); + x.swap(y); + + assert(!x.has_value()); + assert(x.error().i == 10); + assert(x.error().adlSwapCalled); + assert(!y.has_value()); + assert(y.error().i == 5); + assert(y.error().adlSwapCalled); + } + + // this->has_value() && !rhs.has_value() + { + Traced::state s{}; + std::expected e1(std::in_place); + std::expected e2(std::unexpect, s, 10); + + e1.swap(e2); + + assert(!e1.has_value()); + assert(e1.error().data_ == 10); + assert(e2.has_value()); + + assert(s.moveCtorCalled); + assert(s.dtorCalled); + } + + // !this->has_value() && rhs.has_value() + { + Traced::state s{}; + std::expected e1(std::unexpect, s, 10); + std::expected e2(std::in_place); + + e1.swap(e2); + + assert(e1.has_value()); + assert(!e2.has_value()); + assert(e2.error().data_ == 10); + + assert(s.moveCtorCalled); + assert(s.dtorCalled); + } + + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/types.h b/libcxx/test/std/utilities/expected/types.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/types.h @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_STD_UTILITIES_EXPECTED_TYPES_H +#define TEST_STD_UTILITIES_EXPECTED_TYPES_H + +#include + +template +struct TracedBase { + struct state { + bool copyCtorCalled = false; + bool copyAssignCalled = false; + bool moveCtorCalled = false; + bool moveAssignCalled = false; + bool dtorCalled = false; + }; + + state* state_ = nullptr; + bool copiedFromInt = false; + bool movedFromInt = false; + bool copiedFromTmp = false; + bool movedFromTmp = false; + int data_; + + constexpr TracedBase(const int& ii) noexcept(convertNoexcept) : data_(ii) { copiedFromInt = true; } + constexpr TracedBase(int&& ii) noexcept(convertNoexcept) : data_(ii) { movedFromInt = true; } + constexpr TracedBase(state& s, int ii) noexcept : state_(&s), data_(ii) {} + constexpr TracedBase(const TracedBase& other) noexcept(copyMoveNoexcept) : state_(other.state_), data_(other.data_) { + if (state_) { + state_->copyCtorCalled = true; + } else { + copiedFromTmp = true; + } + } + constexpr TracedBase(TracedBase&& other) noexcept(copyMoveNoexcept) : state_(other.state_), data_(other.data_) { + if (state_) { + state_->moveCtorCalled = true; + } else { + movedFromTmp = true; + } + } + constexpr TracedBase& operator=(const TracedBase& other) noexcept(copyMoveNoexcept) { + data_ = other.data_; + state_->copyAssignCalled = true; + return *this; + } + constexpr TracedBase& operator=(TracedBase&& other) noexcept(copyMoveNoexcept) { + data_ = other.data_; + state_->moveAssignCalled = true; + return *this; + } + constexpr ~TracedBase() { + if (state_) { + state_->dtorCalled = true; + } + } +}; + +using Traced = TracedBase; +using TracedNoexcept = TracedBase; + +using MoveThrowConvNoexcept = TracedBase; +using MoveNoexceptConvThrow = TracedBase; +using BothMayThrow = TracedBase; +using BothNoexcept = TracedBase; + +struct ADLSwap { + int i; + bool adlSwapCalled = false; + constexpr ADLSwap(int ii) : i(ii) {} + constexpr friend void swap(ADLSwap& x, ADLSwap& y) { + std::swap(x.i, y.i); + x.adlSwapCalled = true; + y.adlSwapCalled = true; + } +}; + +template +struct TrackedMove { + int i; + int numberOfMoves = 0; + bool swapCalled = false; + + constexpr TrackedMove(int ii) : i(ii) {} + constexpr TrackedMove(TrackedMove&& other) noexcept(Noexcept) + : i(other.i), numberOfMoves(other.numberOfMoves), swapCalled(other.swapCalled) { + ++numberOfMoves; + } + + constexpr friend void swap(TrackedMove& x, TrackedMove& y) { + std::swap(x.i, y.i); + std::swap(x.numberOfMoves, y.numberOfMoves); + x.swapCalled = true; + y.swapCalled = true; + } +}; + +#endif // TEST_STD_UTILITIES_EXPECTED_TYPES_H diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -308,6 +308,10 @@ "values": { "c++17": 201603, "c++20": 201902 }, "headers": ["execution"], "unimplemented": True, + }, { + "name": "__cpp_lib_expected", + "values": { "c++2b": 202202 }, + "headers": ["expected"], }, { "name": "__cpp_lib_filesystem", "values": { "c++17": 201703 }, diff --git a/libcxx/utils/generate_header_inclusion_tests.py b/libcxx/utils/generate_header_inclusion_tests.py --- a/libcxx/utils/generate_header_inclusion_tests.py +++ b/libcxx/utils/generate_header_inclusion_tests.py @@ -68,6 +68,7 @@ "concepts": "20", "coroutine": "20", "cuchar": "11", + "expected": "23", "filesystem": "17", "initializer_list": "11", "optional": "17",