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,925 @@ +// -*- 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 + +#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; + __builtin_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>) // strengthened + 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>) // strengthened + 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, _UfQual>, // + is_constructible<_Err, _OtherErrQual>, // + _Not&>>, // + _Not>>, // + _Not&>>, // + _Not>>, // + _Not&, _Tp>>, // + _Not&&, _Tp>>, // + _Not&, _Tp>>, // + _Not&&, _Tp>>, // + _Not, expected<_Up, _OtherErr>&>>, // + _Not, expected<_Up, _OtherErr>>>, // + _Not, const expected<_Up, _OtherErr>&>>, // + _Not, const expected<_Up, _OtherErr>>> // + >; + +public: + template + requires __can_convert<_Up, _OtherErr, const _Up&, const _OtherErr&>::value + _LIBCPP_HIDE_FROM_ABI constexpr // + explicit(!is_convertible_v || // + !is_convertible_v) // + expected(const expected<_Up, _OtherErr>& __other) // + noexcept((is_nothrow_constructible_v<_Tp, const _Up&> && // + is_nothrow_constructible_v<_Err, const _OtherErr&>)) // strengthened + : __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, _OtherErr, _Up, _OtherErr>::value + _LIBCPP_HIDE_FROM_ABI constexpr // + explicit(!is_convertible_v<_Up, _Tp> || // + !is_convertible_v<_OtherErr, _Err>) // + expected(expected<_Up, _OtherErr>&& __other) // + noexcept(is_nothrow_constructible_v<_Tp, _Up>&& // + is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened + : __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>) // strengthened + : __val_(std::forward<_Up>(__u)), __has_val_(true) {} + + template + requires is_constructible_v<_Err, const _OtherErr&> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) + expected(const unexpected<_OtherErr>& __unex) // strengthened + noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) + : __unex_(__unex.error()), __has_val_(false) {} + + template + requires is_constructible_v<_Err, _OtherErr> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) // + expected(unexpected<_OtherErr>&& __unex) // + noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened + : __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...>) // strengthened + : __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...>) // strengthened + : __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...>) // strengthened + : __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...>) // strengthened + : __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 guarantee, 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>)) // strengthened + 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, _OtherErrQual>, // + is_assignable<_Err&, _OtherErrQual>, // + _Lazy<_Or, + is_nothrow_constructible<_Err, _OtherErrQual>, // + 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<_OtherErr>& __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<_OtherErr>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __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)...); + } + +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>)) + { + auto __swap_val_unex_impl = [&](expected& __with_val, expected& __with_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 guarantee, 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; + }; + + 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))) + requires requires { __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 expected with a E that is not a " + "valid argument for unexpected is ill-formed"); + + template + friend class expected; + + template + using __can_convert = _And< // + is_void<_Up>, // + is_constructible<_Err, _OtherErrQual>, // + _Not, expected<_Up, _OtherErr>&>>, // + _Not, expected<_Up, _OtherErr>>>, // + _Not, const expected<_Up, _OtherErr>&>>, // + _Not, const expected<_Up, _OtherErr>>>>; + +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>) // strengthened + 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, _OtherErr, const _OtherErr&>::value + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) // + expected(const expected<_Up, _OtherErr>& __rhs) // + noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened + : __has_val_(__rhs.__has_val_) { + if (!__rhs.__has_val_) { + std::construct_at(std::addressof(__unex_), __rhs.__unex_); + } + } + + template + requires __can_convert<_Up, _OtherErr, _OtherErr>::value + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) // + expected(expected<_Up, _OtherErr>&& __rhs) // + noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened + : __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 _OtherErr&> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) + expected(const unexpected<_OtherErr>& __unex) // + noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened + : __unex_(__unex.error()), __has_val_(false) {} + + template + requires is_constructible_v<_Err, _OtherErr> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) // + expected(unexpected<_OtherErr>&& __unex) // + noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened + : __unex_(std::move(__unex.error())), __has_val_(false) {} + + _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...>) // strengthened + : __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...>) // strengthened + : __unex_(__il, std::forward<_Args>(__args)...), __has_val_(false) {} + + // [expected.void.dtor], destructor + + _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_)); + } + } + + // [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>)) // strengthened + 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 _OtherErr&> && is_assignable_v<_Err&, const _OtherErr&>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __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, _OtherErr> && is_assignable_v<_Err&, _OtherErr>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __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>) + { + auto __swap_val_unex_impl = [&](expected& __with_val, expected& __with_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; + }; + + 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))) + requires requires { __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_); + } + } + + _LIBCPP_HIDE_FROM_ABI 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: + union { + _Err __unex_; + }; + bool __has_val_; +}; + +_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>) // strengthened + : __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...>) // strengthened + : __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...>) // strengthened + : __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 @@ -11,6 +11,7 @@ #include <__config> #include <__type_traits/integral_constant.h> +#include <__type_traits/is_member_function_pointer.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header 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 @@ -11,6 +11,8 @@ #include <__config> #include <__type_traits/integral_constant.h> +#include <__type_traits/is_reference.h> +#include <__utility/declval.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header 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 @@ -11,6 +11,8 @@ #include <__config> #include <__type_traits/integral_constant.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_cv.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header 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_EXPECTED +#define _LIBCPP_EXPECTED + +/* + 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_EXPECTED + 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/assertions/headers_declare_verbose_abort.sh.cpp b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp --- a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp +++ b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp @@ -306,464 +306,470 @@ using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_47 -#if defined(TEST_47) && !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) -# include +// RUN: %{build} -DTEST_46 +#if defined(TEST_46) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_49 -#if defined(TEST_49) -# include +// RUN: %{build} -DTEST_48 +#if defined(TEST_48) && !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_50 #if defined(TEST_50) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_51 -#if defined(TEST_51) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_FSTREAM) -# include +#if defined(TEST_51) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_52 -#if defined(TEST_52) -# include +#if defined(TEST_52) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_FSTREAM) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_53 -#if defined(TEST_53) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +#if defined(TEST_53) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_54 -#if defined(TEST_54) -# include +#if defined(TEST_54) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_56 -#if defined(TEST_56) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +// RUN: %{build} -DTEST_55 +#if defined(TEST_55) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_57 #if defined(TEST_57) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_58 -#if defined(TEST_58) -# include +#if defined(TEST_58) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_59 -#if defined(TEST_59) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_59) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_60 #if defined(TEST_60) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_61 -#if defined(TEST_61) -# include +#if defined(TEST_61) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_62 -#if defined(TEST_62) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +#if defined(TEST_62) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_63 -#if defined(TEST_63) -# include +#if defined(TEST_63) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_65 -#if defined(TEST_65) -# include +// RUN: %{build} -DTEST_64 +#if defined(TEST_64) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_66 -#if defined(TEST_66) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_66) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_68 -#if defined(TEST_68) -# include +// RUN: %{build} -DTEST_67 +#if defined(TEST_67) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_70 -#if defined(TEST_70) -# include +// RUN: %{build} -DTEST_69 +#if defined(TEST_69) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_71 #if defined(TEST_71) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_72 -#if defined(TEST_72) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +#if defined(TEST_72) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_73 -#if defined(TEST_73) -# include +#if defined(TEST_73) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_74 #if defined(TEST_74) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_75 #if defined(TEST_75) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_76 #if defined(TEST_76) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_77 -#if defined(TEST_77) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_77) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_78 -#if defined(TEST_78) -# include +#if defined(TEST_78) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_79 #if defined(TEST_79) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_80 #if defined(TEST_80) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_81 #if defined(TEST_81) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_82 -#if defined(TEST_82) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_82) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_83 -#if defined(TEST_83) -# include +#if defined(TEST_83) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_84 -#if defined(TEST_84) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +#if defined(TEST_84) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_85 -#if defined(TEST_85) +#if defined(TEST_85) && !defined(_LIBCPP_HAS_NO_THREADS) +# include + using HandlerType = decltype(std::__libcpp_verbose_abort); +#endif + +// RUN: %{build} -DTEST_86 +#if defined(TEST_86) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_87 -#if defined(TEST_87) && !defined(_LIBCPP_HAS_NO_THREADS) +// RUN: %{build} -DTEST_88 +#if defined(TEST_88) && !defined(_LIBCPP_HAS_NO_THREADS) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_88 -#if defined(TEST_88) +// RUN: %{build} -DTEST_89 +#if defined(TEST_89) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_89 -#if defined(TEST_89) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +// RUN: %{build} -DTEST_90 +#if defined(TEST_90) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_90 -#if defined(TEST_90) +// RUN: %{build} -DTEST_91 +#if defined(TEST_91) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_94 -#if defined(TEST_94) +// RUN: %{build} -DTEST_95 +#if defined(TEST_95) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_98 -#if defined(TEST_98) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +// RUN: %{build} -DTEST_99 +#if defined(TEST_99) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_99 -#if defined(TEST_99) +// RUN: %{build} -DTEST_100 +#if defined(TEST_100) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_101 -#if defined(TEST_101) +// RUN: %{build} -DTEST_102 +#if defined(TEST_102) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_102 -#if defined(TEST_102) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +// RUN: %{build} -DTEST_103 +#if defined(TEST_103) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_103 -#if defined(TEST_103) +// RUN: %{build} -DTEST_104 +#if defined(TEST_104) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_105 -#if defined(TEST_105) && !defined(_LIBCPP_HAS_NO_THREADS) -# include - using HandlerType = decltype(std::__libcpp_verbose_abort); -#endif - // RUN: %{build} -DTEST_106 -#if defined(TEST_106) -# include +#if defined(TEST_106) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_107 #if defined(TEST_107) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_108 #if defined(TEST_108) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_109 #if defined(TEST_109) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_111 -#if defined(TEST_111) -# include +// RUN: %{build} -DTEST_110 +#if defined(TEST_110) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_112 #if defined(TEST_112) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_113 #if defined(TEST_113) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_114 #if defined(TEST_114) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_115 #if defined(TEST_115) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_116 #if defined(TEST_116) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_117 #if defined(TEST_117) -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif -// RUN: %{build} -DTEST_120 -#if defined(TEST_120) && __cplusplus >= 201103L -# include +// RUN: %{build} -DTEST_118 +#if defined(TEST_118) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_121 -#if defined(TEST_121) && __cplusplus >= 201103L && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) -# include +#if defined(TEST_121) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_122 -#if defined(TEST_122) && __cplusplus >= 201103L -# include +#if defined(TEST_122) && __cplusplus >= 201103L && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_123 #if defined(TEST_123) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_124 #if defined(TEST_124) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_125 #if defined(TEST_125) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_126 #if defined(TEST_126) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_127 #if defined(TEST_127) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_128 #if defined(TEST_128) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_129 #if defined(TEST_129) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_130 -#if defined(TEST_130) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L -# include +#if defined(TEST_130) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_131 -#if defined(TEST_131) && __cplusplus >= 201103L -# include +#if defined(TEST_131) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_132 #if defined(TEST_132) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_133 #if defined(TEST_133) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_134 #if defined(TEST_134) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_135 #if defined(TEST_135) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_136 #if defined(TEST_136) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_137 #if defined(TEST_137) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_138 #if defined(TEST_138) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_139 -#if defined(TEST_139) -# include +#if defined(TEST_139) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif // RUN: %{build} -DTEST_140 #if defined(TEST_140) +# include + using HandlerType = decltype(std::__libcpp_verbose_abort); +#endif + +// RUN: %{build} -DTEST_141 +#if defined(TEST_141) # include using HandlerType = decltype(std::__libcpp_verbose_abort); #endif 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/modules_include.sh.cpp b/libcxx/test/libcxx/modules_include.sh.cpp --- a/libcxx/test/libcxx/modules_include.sh.cpp +++ b/libcxx/test/libcxx/modules_include.sh.cpp @@ -232,382 +232,386 @@ #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_46 #if defined(TEST_46) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_47 -#if defined(TEST_47) && !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) -#include +#if defined(TEST_47) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_48 -#if defined(TEST_48) -#include +#if defined(TEST_48) && !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_49 #if defined(TEST_49) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_50 #if defined(TEST_50) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_51 -#if defined(TEST_51) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_FSTREAM) -#include +#if defined(TEST_51) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_52 -#if defined(TEST_52) -#include +#if defined(TEST_52) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_FSTREAM) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_53 -#if defined(TEST_53) && !defined(_LIBCPP_HAS_NO_THREADS) -#include +#if defined(TEST_53) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_54 -#if defined(TEST_54) -#include +#if defined(TEST_54) && !defined(_LIBCPP_HAS_NO_THREADS) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_55 #if defined(TEST_55) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_56 -#if defined(TEST_56) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#if defined(TEST_56) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_57 #if defined(TEST_57) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_58 -#if defined(TEST_58) -#include +#if defined(TEST_58) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_59 -#if defined(TEST_59) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#if defined(TEST_59) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_60 #if defined(TEST_60) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_61 -#if defined(TEST_61) -#include +#if defined(TEST_61) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_62 -#if defined(TEST_62) && !defined(_LIBCPP_HAS_NO_THREADS) -#include +#if defined(TEST_62) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_63 -#if defined(TEST_63) -#include +#if defined(TEST_63) && !defined(_LIBCPP_HAS_NO_THREADS) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_64 #if defined(TEST_64) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_65 #if defined(TEST_65) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_66 -#if defined(TEST_66) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#if defined(TEST_66) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_67 #if defined(TEST_67) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_68 -#if defined(TEST_68) -#include +#if defined(TEST_68) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_69 #if defined(TEST_69) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_70 #if defined(TEST_70) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_71 #if defined(TEST_71) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_72 -#if defined(TEST_72) && !defined(_LIBCPP_HAS_NO_THREADS) -#include +#if defined(TEST_72) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_73 -#if defined(TEST_73) -#include +#if defined(TEST_73) && !defined(_LIBCPP_HAS_NO_THREADS) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_74 #if defined(TEST_74) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_75 #if defined(TEST_75) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_76 #if defined(TEST_76) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_77 -#if defined(TEST_77) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#if defined(TEST_77) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_78 -#if defined(TEST_78) -#include +#if defined(TEST_78) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_79 #if defined(TEST_79) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_80 #if defined(TEST_80) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_81 #if defined(TEST_81) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_82 -#if defined(TEST_82) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#if defined(TEST_82) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_83 -#if defined(TEST_83) -#include +#if defined(TEST_83) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_84 -#if defined(TEST_84) && !defined(_LIBCPP_HAS_NO_THREADS) -#include +#if defined(TEST_84) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_85 -#if defined(TEST_85) -#include +#if defined(TEST_85) && !defined(_LIBCPP_HAS_NO_THREADS) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_86 #if defined(TEST_86) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_87 -#if defined(TEST_87) && !defined(_LIBCPP_HAS_NO_THREADS) -#include +#if defined(TEST_87) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_88 -#if defined(TEST_88) -#include +#if defined(TEST_88) && !defined(_LIBCPP_HAS_NO_THREADS) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_89 -#if defined(TEST_89) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#if defined(TEST_89) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_90 -#if defined(TEST_90) -#include +#if defined(TEST_90) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_91 -#if defined(TEST_91) && __cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS) -#include +#if defined(TEST_91) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_92 -#if defined(TEST_92) -#include +#if defined(TEST_92) && __cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_93 #if defined(TEST_93) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_94 #if defined(TEST_94) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_95 #if defined(TEST_95) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_96 #if defined(TEST_96) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_97 #if defined(TEST_97) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_98 -#if defined(TEST_98) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#if defined(TEST_98) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_99 -#if defined(TEST_99) -#include +#if defined(TEST_99) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_100 #if defined(TEST_100) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_101 #if defined(TEST_101) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_102 -#if defined(TEST_102) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -#include +#if defined(TEST_102) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_103 -#if defined(TEST_103) -#include +#if defined(TEST_103) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_104 #if defined(TEST_104) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_105 -#if defined(TEST_105) && !defined(_LIBCPP_HAS_NO_THREADS) -#include +#if defined(TEST_105) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_106 -#if defined(TEST_106) -#include +#if defined(TEST_106) && !defined(_LIBCPP_HAS_NO_THREADS) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_107 #if defined(TEST_107) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_108 #if defined(TEST_108) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_109 #if defined(TEST_109) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_110 #if defined(TEST_110) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_111 #if defined(TEST_111) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_112 #if defined(TEST_112) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_113 #if defined(TEST_113) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_114 #if defined(TEST_114) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_115 #if defined(TEST_115) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_116 #if defined(TEST_116) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_117 #if defined(TEST_117) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_118 -#if defined(TEST_118) && !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) -#include +#if defined(TEST_118) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_119 #if defined(TEST_119) && !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_120 -#if defined(TEST_120) && __cplusplus >= 201103L -#include +#if defined(TEST_120) && !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_121 -#if defined(TEST_121) && __cplusplus >= 201103L && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) -#include +#if defined(TEST_121) && __cplusplus >= 201103L +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_122 -#if defined(TEST_122) && __cplusplus >= 201103L -#include +#if defined(TEST_122) && __cplusplus >= 201103L && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_123 #if defined(TEST_123) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_124 #if defined(TEST_124) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_125 #if defined(TEST_125) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_126 #if defined(TEST_126) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_127 #if defined(TEST_127) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_128 #if defined(TEST_128) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_129 #if defined(TEST_129) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_130 -#if defined(TEST_130) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L -#include +#if defined(TEST_130) && __cplusplus >= 201103L +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_131 -#if defined(TEST_131) && __cplusplus >= 201103L -#include +#if defined(TEST_131) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_132 #if defined(TEST_132) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_133 #if defined(TEST_133) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_134 #if defined(TEST_134) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_135 #if defined(TEST_135) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_136 #if defined(TEST_136) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_137 #if defined(TEST_137) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_138 #if defined(TEST_138) && __cplusplus >= 201103L -#include +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_139 -#if defined(TEST_139) -#include +#if defined(TEST_139) && __cplusplus >= 201103L +#include #endif // RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_140 #if defined(TEST_140) +#include +#endif +// RUN: %{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_141 +#if defined(TEST_141) #include #endif // GENERATED-MARKER 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,312 +252,316 @@ #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 -fshow-skipped-includes -fsyntax-only -DTEST_46 2> %t/header.expected +#if defined(TEST_46) +#include +#endif +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_48 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_50 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_51 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_52 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_53 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_54 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_55 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_57 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_58 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_59 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_60 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_61 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_62 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_63 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_64 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_66 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_67 2> %t/header.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 -fshow-skipped-includes -fsyntax-only -DTEST_69 2> %t/header.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) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_71 2> %t/header.memory +#if defined(TEST_71) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_71 2> %t/header.memory_resource -#if defined(TEST_71) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_72 2> %t/header.memory_resource +#if defined(TEST_72) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_72 2> %t/header.mutex -#if defined(TEST_72) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_73 2> %t/header.mutex +#if defined(TEST_73) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_73 2> %t/header.new -#if defined(TEST_73) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_74 2> %t/header.new +#if defined(TEST_74) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_74 2> %t/header.numbers -#if defined(TEST_74) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_75 2> %t/header.numbers +#if defined(TEST_75) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_75 2> %t/header.numeric -#if defined(TEST_75) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_76 2> %t/header.numeric +#if defined(TEST_76) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_76 2> %t/header.optional -#if defined(TEST_76) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_77 2> %t/header.optional +#if defined(TEST_77) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_77 2> %t/header.ostream -#if defined(TEST_77) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_78 2> %t/header.ostream +#if defined(TEST_78) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_78 2> %t/header.queue -#if defined(TEST_78) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_79 2> %t/header.queue +#if defined(TEST_79) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_79 2> %t/header.random -#if defined(TEST_79) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_80 2> %t/header.random +#if defined(TEST_80) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_80 2> %t/header.ranges -#if defined(TEST_80) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_81 2> %t/header.ranges +#if defined(TEST_81) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_81 2> %t/header.ratio -#if defined(TEST_81) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_82 2> %t/header.ratio +#if defined(TEST_82) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_82 2> %t/header.regex -#if defined(TEST_82) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_83 2> %t/header.regex +#if defined(TEST_83) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_83 2> %t/header.scoped_allocator -#if defined(TEST_83) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_84 2> %t/header.scoped_allocator +#if defined(TEST_84) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_84 2> %t/header.semaphore -#if defined(TEST_84) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_85 2> %t/header.semaphore +#if defined(TEST_85) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_85 2> %t/header.set -#if defined(TEST_85) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_86 2> %t/header.set +#if defined(TEST_86) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_87 2> %t/header.shared_mutex -#if defined(TEST_87) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_88 2> %t/header.shared_mutex +#if defined(TEST_88) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_88 2> %t/header.span -#if defined(TEST_88) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_89 2> %t/header.span +#if defined(TEST_89) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_89 2> %t/header.sstream -#if defined(TEST_89) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_90 2> %t/header.sstream +#if defined(TEST_90) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_90 2> %t/header.stack -#if defined(TEST_90) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_91 2> %t/header.stack +#if defined(TEST_91) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_94 2> %t/header.stdexcept -#if defined(TEST_94) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_95 2> %t/header.stdexcept +#if defined(TEST_95) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_98 2> %t/header.streambuf -#if defined(TEST_98) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_99 2> %t/header.streambuf +#if defined(TEST_99) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_99 2> %t/header.string -#if defined(TEST_99) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_100 2> %t/header.string +#if defined(TEST_100) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_101 2> %t/header.string_view -#if defined(TEST_101) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_102 2> %t/header.string_view +#if defined(TEST_102) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_102 2> %t/header.strstream -#if defined(TEST_102) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_103 2> %t/header.strstream +#if defined(TEST_103) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_103 2> %t/header.system_error -#if defined(TEST_103) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_104 2> %t/header.system_error +#if defined(TEST_104) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_105 2> %t/header.thread -#if defined(TEST_105) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_106 2> %t/header.thread +#if defined(TEST_106) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_106 2> %t/header.tuple -#if defined(TEST_106) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_107 2> %t/header.tuple +#if defined(TEST_107) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_107 2> %t/header.type_traits -#if defined(TEST_107) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_108 2> %t/header.type_traits +#if defined(TEST_108) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_108 2> %t/header.typeindex -#if defined(TEST_108) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_109 2> %t/header.typeindex +#if defined(TEST_109) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_109 2> %t/header.typeinfo -#if defined(TEST_109) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_110 2> %t/header.typeinfo +#if defined(TEST_110) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_111 2> %t/header.unordered_map -#if defined(TEST_111) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_112 2> %t/header.unordered_map +#if defined(TEST_112) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_112 2> %t/header.unordered_set -#if defined(TEST_112) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_113 2> %t/header.unordered_set +#if defined(TEST_113) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_113 2> %t/header.utility -#if defined(TEST_113) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_114 2> %t/header.utility +#if defined(TEST_114) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_114 2> %t/header.valarray -#if defined(TEST_114) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_115 2> %t/header.valarray +#if defined(TEST_115) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_115 2> %t/header.variant -#if defined(TEST_115) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_116 2> %t/header.variant +#if defined(TEST_116) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_116 2> %t/header.vector -#if defined(TEST_116) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_117 2> %t/header.vector +#if defined(TEST_117) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_117 2> %t/header.version -#if defined(TEST_117) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_118 2> %t/header.version +#if defined(TEST_118) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_120 2> %t/header.experimental_algorithm -#if defined(TEST_120) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_121 2> %t/header.experimental_algorithm +#if defined(TEST_121) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_121 2> %t/header.experimental_coroutine -#if defined(TEST_121) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_122 2> %t/header.experimental_coroutine +#if defined(TEST_122) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_122 2> %t/header.experimental_deque -#if defined(TEST_122) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_123 2> %t/header.experimental_deque +#if defined(TEST_123) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_123 2> %t/header.experimental_forward_list -#if defined(TEST_123) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_124 2> %t/header.experimental_forward_list +#if defined(TEST_124) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_124 2> %t/header.experimental_functional -#if defined(TEST_124) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_125 2> %t/header.experimental_functional +#if defined(TEST_125) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_125 2> %t/header.experimental_iterator -#if defined(TEST_125) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_126 2> %t/header.experimental_iterator +#if defined(TEST_126) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_126 2> %t/header.experimental_list -#if defined(TEST_126) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_127 2> %t/header.experimental_list +#if defined(TEST_127) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_127 2> %t/header.experimental_map -#if defined(TEST_127) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_128 2> %t/header.experimental_map +#if defined(TEST_128) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_128 2> %t/header.experimental_memory_resource -#if defined(TEST_128) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_129 2> %t/header.experimental_memory_resource +#if defined(TEST_129) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_129 2> %t/header.experimental_propagate_const -#if defined(TEST_129) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_130 2> %t/header.experimental_propagate_const +#if defined(TEST_130) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_130 2> %t/header.experimental_regex -#if defined(TEST_130) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_131 2> %t/header.experimental_regex +#if defined(TEST_131) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_131 2> %t/header.experimental_set -#if defined(TEST_131) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_132 2> %t/header.experimental_set +#if defined(TEST_132) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_132 2> %t/header.experimental_simd -#if defined(TEST_132) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_133 2> %t/header.experimental_simd +#if defined(TEST_133) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_133 2> %t/header.experimental_string -#if defined(TEST_133) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_134 2> %t/header.experimental_string +#if defined(TEST_134) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_134 2> %t/header.experimental_type_traits -#if defined(TEST_134) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_135 2> %t/header.experimental_type_traits +#if defined(TEST_135) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_135 2> %t/header.experimental_unordered_map -#if defined(TEST_135) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_136 2> %t/header.experimental_unordered_map +#if defined(TEST_136) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_136 2> %t/header.experimental_unordered_set -#if defined(TEST_136) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_137 2> %t/header.experimental_unordered_set +#if defined(TEST_137) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_137 2> %t/header.experimental_utility -#if defined(TEST_137) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_138 2> %t/header.experimental_utility +#if defined(TEST_138) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_138 2> %t/header.experimental_vector -#if defined(TEST_138) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_139 2> %t/header.experimental_vector +#if defined(TEST_139) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_139 2> %t/header.ext_hash_map -#if defined(TEST_139) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_140 2> %t/header.ext_hash_map +#if defined(TEST_140) #include #endif -// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_140 2> %t/header.ext_hash_set -#if defined(TEST_140) +// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_141 2> %t/header.ext_hash_set +#if defined(TEST_141) #include #endif // RUN: %{python} %S/transitive_includes_to_csv.py %t > %t/transitive_includes.csv diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -202,6 +202,12 @@ exception type_traits exception version execution version +expected cstddef +expected exception +expected initializer_list +expected new +expected type_traits +expected version experimental/algorithm algorithm experimental/algorithm cstddef experimental/algorithm type_traits diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -202,6 +202,12 @@ exception type_traits exception version execution version +expected cstddef +expected exception +expected initializer_list +expected new +expected type_traits +expected version experimental/algorithm algorithm experimental/algorithm cstddef experimental/algorithm type_traits diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -202,6 +202,12 @@ exception type_traits exception version execution version +expected cstddef +expected exception +expected initializer_list +expected new +expected type_traits +expected version experimental/algorithm algorithm experimental/algorithm cstddef experimental/algorithm type_traits diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -202,6 +202,12 @@ exception type_traits exception version execution version +expected cstddef +expected exception +expected initializer_list +expected new +expected type_traits +expected version experimental/algorithm algorithm experimental/algorithm cstddef experimental/algorithm type_traits diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -213,6 +213,12 @@ exception type_traits exception version execution version +expected cstddef +expected exception +expected initializer_list +expected new +expected type_traits +expected version experimental/algorithm algorithm experimental/algorithm cstddef experimental/algorithm type_traits diff --git a/libcxx/test/libcxx/transitive_includes/cxx2b.csv b/libcxx/test/libcxx/transitive_includes/cxx2b.csv --- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv @@ -167,6 +167,12 @@ exception type_traits exception version execution version +expected cstddef +expected exception +expected initializer_list +expected new +expected type_traits +expected version experimental/algorithm algorithm experimental/algorithm cstddef experimental/algorithm type_traits 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/noexcept.extension.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/noexcept.extension.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/noexcept.extension.compile.pass.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// 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 libc++ noexcept extensions on operations of std::expected + +#include +#include +#include + +#include "../types.h" + +// constexpr expected(); +static_assert(std::is_nothrow_default_constructible_v>); +static_assert(!std::is_nothrow_default_constructible_v>); + +// expected(const expected&) +static_assert(std::is_nothrow_copy_constructible_v>); +static_assert(!std::is_nothrow_copy_constructible_v>); +static_assert(!std::is_nothrow_copy_constructible_v>); + +// expected(const expected&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + const std::expected&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + const std::expected&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + const std::expected&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, // + const std::expected&>); + +// expected(expected&&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::expected&&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::expected&&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::expected&&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, // + std::expected&&>); + +// expected(U&&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + const int&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + const int&>); + +// expected(const unexpected&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + const std::unexpected&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + const std::unexpected&>); + +// expected(unexpected&&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::unexpected&&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::unexpected&&>); + +// expected(in_place_t, _Args&&...); +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::in_place_t, + const int&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::in_place_t, + const int&>); + +// expected(in_place_t, initializer_list, _Args&&...); +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::in_place_t, + std::initializer_list>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::in_place_t, + std::initializer_list>); + +// expected(unexpect_t, _Args&&...); +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::unexpect_t, + const int&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::unexpect_t, + const int&>); + +// expected(unexpect_t, initializer_list, _Args&&...); +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::unexpect_t, + std::initializer_list>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::unexpect_t, + std::initializer_list>); + +// expected& operator=(const expected&) +static_assert(std::is_nothrow_copy_assignable_v>); +static_assert(!std::is_nothrow_copy_assignable_v>); +static_assert(!std::is_nothrow_copy_assignable_v>); +static_assert(!std::is_nothrow_copy_assignable_v>); +static_assert(!std::is_nothrow_copy_assignable_v>); 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/noexcept.extension.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.unexpected/noexcept.extension.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.unexpected/noexcept.extension.compile.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// 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 libc++ noexcept extensions on operations of std::unexpected + +#include +#include +#include + +#include "../types.h" + +// unexpected(Error&&); +static_assert(std::is_nothrow_constructible_v< // + std::unexpected, + const int&>); +static_assert(!std::is_nothrow_constructible_v< // + std::unexpected, + const int&>); + + +// unexpected(in_place_t, _Args&&...); +static_assert(std::is_nothrow_constructible_v< // + std::unexpected, + std::in_place_t, + const int&>); +static_assert(!std::is_nothrow_constructible_v< // + std::unexpected, + std::in_place_t, + const int&>); + +// unexpected(in_place_t, initializer_list, _Args&&...); +static_assert(std::is_nothrow_constructible_v< // + std::unexpected, + std::in_place_t, + std::initializer_list>); +static_assert(!std::is_nothrow_constructible_v< // + std::unexpected, + std::in_place_t, + std::initializer_list>); 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/expected.void/noexcept.extension.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/noexcept.extension.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.void/noexcept.extension.compile.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// 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 libc++ noexcept extensions on operations of std::expected + +#include +#include +#include + +#include "../types.h" + +// expected(const expected&) +static_assert(std::is_nothrow_copy_constructible_v>); +static_assert(!std::is_nothrow_copy_constructible_v>); + + +// expected(const expected&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + const std::expected&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + const std::expected&>); + + +// expected(expected&&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::expected&&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::expected&&>); + +// expected(const unexpected&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + const std::unexpected&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + const std::unexpected&>); + +// expected(unexpected&&) +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::unexpected&&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::unexpected&&>); + + +// expected(unexpect_t, _Args&&...); +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::unexpect_t, + const int&>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::unexpect_t, + const int&>); + +// expected(unexpect_t, initializer_list, _Args&&...); +static_assert(std::is_nothrow_constructible_v< // + std::expected, + std::unexpect_t, + std::initializer_list>); +static_assert(!std::is_nothrow_constructible_v< // + std::expected, + std::unexpect_t, + std::initializer_list>); + +// expected& operator=(const expected&) +static_assert(std::is_nothrow_copy_assignable_v>); +static_assert(!std::is_nothrow_copy_assignable_v>); +static_assert(!std::is_nothrow_copy_assignable_v>); diff --git a/libcxx/test/libcxx/utilities/expected/types.h b/libcxx/test/libcxx/utilities/expected/types.h new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/types.h @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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_LIBCXX_UTILITIES_EXPECTED_TYPES_H +#define TEST_LIBCXX_UTILITIES_EXPECTED_TYPES_H + +#include + +struct DefaultMayThrow { + DefaultMayThrow(); +}; + +struct CopyMayThrow { + CopyMayThrow(const CopyMayThrow&); +}; + +struct ConvertFromCopyIntMayThrow { + ConvertFromCopyIntMayThrow(const int&); + ConvertFromCopyIntMayThrow(int&&) noexcept; +}; + +struct ConvertFromMoveIntMayThrow { + ConvertFromMoveIntMayThrow(const int&) noexcept; + ConvertFromMoveIntMayThrow(int&&); +}; + +struct ConvertFromInitializerListNoexcept { + ConvertFromInitializerListNoexcept(std::initializer_list) noexcept; +}; + +struct ConvertFromInitializerListMayThrow { + ConvertFromInitializerListMayThrow(std::initializer_list); +}; + +struct CopyConstructMayThrow { + CopyConstructMayThrow(const CopyConstructMayThrow&); + CopyConstructMayThrow& operator=(CopyConstructMayThrow const&) noexcept; +}; + +struct CopyAssignMayThrow { + CopyAssignMayThrow(const CopyAssignMayThrow&) noexcept; + CopyAssignMayThrow& operator=(CopyAssignMayThrow const&); +}; + + +#endif // TEST_LIBCXX_UTILITIES_EXPECTED_TYPES_H 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,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 + +// explicit bad_expected_access(E e); + +// Effects: Initializes unex with std::move(e). + +#include +#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,338 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 + 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,291 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 ThrowOnCopyMoveMayThrow { + ThrowOnCopyMoveMayThrow() = default; + ThrowOnCopyMoveMayThrow(const ThrowOnCopyMoveMayThrow&) { throw Except{}; }; + ThrowOnCopyMoveMayThrow& operator=(const ThrowOnCopyMoveMayThrow&) = default; + ThrowOnCopyMoveMayThrow(ThrowOnCopyMoveMayThrow&&) 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,302 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 + // 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,200 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 + 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,200 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 + 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,86 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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,120 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 + +#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,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(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 + +#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,120 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 + +#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,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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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,221 @@ +//===----------------------------------------------------------------------===// +// 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" + +// Test Constraints: +struct NotSwappable { + NotSwappable operator=(const NotSwappable&) = delete; +}; +void swap(NotSwappable&, NotSwappable&) = delete; + +static_assert(std::is_swappable_v>); + +// !is_swappable_v +static_assert(!std::is_swappable_v>); + +// !is_swappable_v +static_assert(!std::is_swappable_v>); + +struct NotMoveContructible { + NotMoveContructible(NotMoveContructible&&) = delete; + friend void swap(NotMoveContructible&, NotMoveContructible&) {} +}; + +// !is_move_constructible_v +static_assert(!std::is_swappable_v>); + +// !is_move_constructible_v +static_assert(!std::is_swappable_v>); + +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow&&) noexcept(false); + friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {} +}; + +// !is_nothrow_move_constructible_v && is_nothrow_move_constructible_v +static_assert(std::is_swappable_v>); + +// is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v +static_assert(std::is_swappable_v>); + +// !is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v +static_assert(!std::is_swappable_v>); + +// Test noexcept +static_assert(std::is_nothrow_swappable_v>); + +// !is_nothrow_move_constructible_v +static_assert(!std::is_nothrow_swappable_v>); + +// !is_nothrow_move_constructible_v +static_assert(!std::is_nothrow_swappable_v>); + +struct SwapMayThrow { + friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {} +}; + +// !is_nothrow_swappable_v +static_assert(!std::is_nothrow_swappable_v>); + +// !is_nothrow_swappable_v +static_assert(!std::is_nothrow_swappable_v>); + +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 + // !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,239 @@ +//===----------------------------------------------------------------------===// +// 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 + // !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,126 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + std::expected e1(std::in_place); + std::expected e2(std::unexpect); + try { + e1 = e2; + assert(false); + } catch (Except) { + assert(e1.has_value()); + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + 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,151 @@ +//===----------------------------------------------------------------------===// +// 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 +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + std::expected e1(std::in_place); + std::expected e2(std::unexpect); + try { + e1 = std::move(e2); + assert(false); + } catch (Except) { + assert(e1.has_value()); + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + 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,117 @@ +//===----------------------------------------------------------------------===// +// 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 +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + std::expected e1(std::in_place); + std::unexpected un(std::in_place); + try { + e1 = un; + assert(false); + } catch (Except) { + assert(e1.has_value()); + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + 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,199 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 + std::expected e1(std::in_place); + std::unexpected un(std::in_place); + try { + e1 = std::move(un); + assert(false); + } catch (Except) { + assert(e1.has_value()); + } +#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,60 @@ +//===----------------------------------------------------------------------===// +// 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 + +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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,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(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 + +#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,118 @@ +//===----------------------------------------------------------------------===// +// 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 +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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 + +#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,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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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,164 @@ +//===----------------------------------------------------------------------===// +// 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 +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(swap(x,y))); + +#include +#include +#include +#include + +#include "../../types.h" +#include "test_macros.h" + +// Test constraint +static_assert(std::is_swappable_v>); + +struct NotSwappable { + NotSwappable& operator=(const NotSwappable&) = delete; +}; +void swap(NotSwappable&, NotSwappable&) = delete; + +// !is_swappable_v +static_assert(!std::is_swappable_v>); + +struct NotMoveContructible { + NotMoveContructible(NotMoveContructible&&) = delete; + friend void swap(NotMoveContructible&, NotMoveContructible&) {} +}; + +// !is_move_constructible_v +static_assert(!std::is_swappable_v>); + +// Test noexcept +struct MoveMayThrow { + MoveMayThrow(MoveMayThrow&&) noexcept(false); + friend void swap(MoveMayThrow&, MoveMayThrow&) 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; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + // !e1.has_value() && e2.has_value() + { + bool e1Destroyed = false; + std::expected e1(std::unexpect, e1Destroyed); + std::expected e2(std::in_place); + try { + swap(e1, e2); + assert(false); + } catch (Except) { + assert(!e1.has_value()); + assert(e2.has_value()); + assert(!e1Destroyed); + } + } + + // e1.has_value() && !e2.has_value() + { + bool e2Destroyed = false; + std::expected e1(std::in_place); + std::expected e2(std::unexpect, e2Destroyed); + try { + swap(e1, e2); + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(!e2.has_value()); + assert(!e2Destroyed); + } + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + 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,173 @@ +//===----------------------------------------------------------------------===// +// 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 +// Older Clangs do not support the C++20 feature to constrain destructors +// XFAIL: clang-14, apple-clang-14 + +// 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; +} + +void testException() { +#ifndef TEST_HAS_NO_EXCEPTIONS + // !e1.has_value() && e2.has_value() + { + bool e1Destroyed = false; + std::expected e1(std::unexpect, e1Destroyed); + std::expected e2(std::in_place); + try { + e1.swap(e2); + assert(false); + } catch (Except) { + assert(!e1.has_value()); + assert(e2.has_value()); + assert(!e1Destroyed); + } + } + + // e1.has_value() && !e2.has_value() + { + bool e2Destroyed = false; + std::expected e1(std::in_place); + std::expected e2(std::unexpect, e2Destroyed); + try { + e1.swap(e2); + assert(false); + } catch (Except) { + assert(e1.has_value()); + assert(!e2.has_value()); + assert(!e2Destroyed); + } + } +#endif +} + +int main(int, char**) { + test(); + static_assert(test()); + testException(); + 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,145 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include "test_macros.h" + +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; + } +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct Except {}; + +struct ThrowOnCopyConstruct { + ThrowOnCopyConstruct() = default; + ThrowOnCopyConstruct(const ThrowOnCopyConstruct&) { throw Except{}; } + ThrowOnCopyConstruct& operator=(const ThrowOnCopyConstruct&) = default; +}; + +struct ThrowOnMoveConstruct { + ThrowOnMoveConstruct() = default; + ThrowOnMoveConstruct(ThrowOnMoveConstruct&&) { throw Except{}; } + ThrowOnMoveConstruct& operator=(ThrowOnMoveConstruct&&) = default; +}; + +struct ThrowOnConvert { + ThrowOnConvert() = default; + ThrowOnConvert(const int&) { throw Except{}; } + ThrowOnConvert(int&&) { throw Except{}; } + ThrowOnConvert(const ThrowOnConvert&) noexcept(false) {} + ThrowOnConvert& operator=(const ThrowOnConvert&) = default; + ThrowOnConvert(ThrowOnConvert&&) noexcept(false) {} + ThrowOnConvert& operator=(ThrowOnConvert&&) = default; +}; + +struct ThrowOnMove { + bool* destroyed = nullptr; + ThrowOnMove() = default; + ThrowOnMove(bool& d) : destroyed(&d) {} + ThrowOnMove(ThrowOnMove&&) { throw Except{}; }; + ThrowOnMove& operator=(ThrowOnMove&&) = default; + ~ThrowOnMove() { + if (destroyed) { + *destroyed = true; + } + } +}; + +#endif + +#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",