| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class U, class G> | ||
| // constexpr explicit(see below) expected(const expected<U, G>&); | ||
| // | ||
| // Let: | ||
| // - UF be const U& | ||
| // - GF be const G& | ||
| // | ||
| // Constraints: | ||
| // - is_constructible_v<T, UF> is true; and | ||
| // - is_constructible_v<E, GF> is true; and | ||
| // - is_constructible_v<T, expected<U, G>&> is false; and | ||
| // - is_constructible_v<T, expected<U, G>> is false; and | ||
| // - is_constructible_v<T, const expected<U, G>&> is false; and | ||
| // - is_constructible_v<T, const expected<U, G>> is false; and | ||
| // - is_convertible_v<expected<U, G>&, T> is false; and | ||
| // - is_convertible_v<expected<U, G>&&, T> is false; and | ||
| // - is_convertible_v<const expected<U, G>&, T> is false; and | ||
| // - is_convertible_v<const expected<U, G>&&, T> is false; and | ||
| // - is_constructible_v<unexpected<E>, expected<U, G>&> is false; and | ||
| // - is_constructible_v<unexpected<E>, expected<U, G>> is false; and | ||
| // - is_constructible_v<unexpected<E>, const expected<U, G>&> is false; and | ||
| // - is_constructible_v<unexpected<E>, const expected<U, G>> is false. | ||
| // | ||
| // Effects: If rhs.has_value(), direct-non-list-initializes val with std::forward<UF>(*rhs). Otherwise, direct-non-list-initializes unex with std::forward<GF>(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<UF, T> || !is_convertible_v<GF, E>. | ||
|
|
||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints: | ||
| template <class T1, class Err1, class T2, class Err2> | ||
| concept canCstrFromExpected = std::is_constructible_v<std::expected<T1, Err1>, const std::expected<T2, Err2>&>; | ||
|
|
||
| struct CtorFromInt { | ||
| CtorFromInt(int); | ||
| }; | ||
|
|
||
| static_assert(canCstrFromExpected<CtorFromInt, int, int, int>); | ||
|
|
||
| struct NoCtorFromInt {}; | ||
|
|
||
| // !is_constructible_v<T, UF> | ||
| static_assert(!canCstrFromExpected<NoCtorFromInt, int, int, int>); | ||
|
|
||
| // !is_constructible_v<E, GF> | ||
| static_assert(!canCstrFromExpected<int, NoCtorFromInt, int, int>); | ||
|
|
||
| template <class T> | ||
| struct CtorFrom { | ||
| explicit CtorFrom(int) | ||
| requires(!std::same_as<T, int>); | ||
| explicit CtorFrom(T); | ||
| explicit CtorFrom(auto&&) = delete; | ||
| }; | ||
|
|
||
| // is_constructible_v<T, expected<U, G>&> | ||
| static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int>&>, int, int, int>); | ||
|
|
||
| // is_constructible_v<T, expected<U, G>> | ||
| static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int>&&>, int, int, int>); | ||
|
|
||
| // is_constructible_v<T, expected<U, G>&> | ||
| // note that this is true because it is covered by the other overload | ||
| // template<class U = T> 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<CtorFrom<std::expected<int, int> const&>, int, int, int>); | ||
|
|
||
| // is_constructible_v<T, expected<U, G>> | ||
| static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int> const&&>, int, int, int>); | ||
|
|
||
| template <class T> | ||
| struct ConvertFrom { | ||
| ConvertFrom(int) | ||
| requires(!std::same_as<T, int>); | ||
| ConvertFrom(T); | ||
| ConvertFrom(auto&&) = delete; | ||
| }; | ||
|
|
||
| // is_convertible_v<expected<U, G>&, T> | ||
| static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int>&>, int, int, int>); | ||
|
|
||
| // is_convertible_v<expected<U, G>&&, T> | ||
| static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int>&&>, int, int, int>); | ||
|
|
||
| // is_convertible_v<const expected<U, G>&, T> | ||
| // note that this is true because it is covered by the other overload | ||
| // template<class U = T> 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<ConvertFrom<std::expected<int, int> const&>, int, int, int>); | ||
|
|
||
| // is_convertible_v<const expected<U, G>&&, T> | ||
| static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int> const&&>, int, int, int>); | ||
|
|
||
| // Note for below 4 tests, because their E is constructible from cvref of std::expected<int, int>, | ||
| // unexpected<E> will be constructible from cvref of std::expected<int, int> | ||
| // is_constructible_v<unexpected<E>, expected<U, G>&> | ||
| static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&>, int, int>); | ||
|
|
||
| // is_constructible_v<unexpected<E>, expected<U, G>> | ||
| static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&&>, int, int>); | ||
|
|
||
| // is_constructible_v<unexpected<E>, const expected<U, G>&> is false | ||
| static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&>, int, int>); | ||
|
|
||
| // is_constructible_v<unexpected<E>, const expected<U, G>> | ||
| static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&&>, int, int>); | ||
|
|
||
| // test explicit | ||
| static_assert(std::is_convertible_v<const std::expected<int, int>&, std::expected<short, long>>); | ||
|
|
||
| // !is_convertible_v<UF, T> | ||
| static_assert(std::is_constructible_v<std::expected<CtorFrom<int>, int>, const std::expected<int, int>&>); | ||
| static_assert(!std::is_convertible_v<const std::expected<int, int>&, std::expected<CtorFrom<int>, int>>); | ||
|
|
||
| // !is_convertible_v<GF, E>. | ||
| static_assert(std::is_constructible_v<std::expected<int, CtorFrom<int>>, const std::expected<int, int>&>); | ||
| static_assert(!std::is_convertible_v<const std::expected<int, int>&, std::expected<int, CtorFrom<int>>>); | ||
|
|
||
| struct Data { | ||
| int i; | ||
| constexpr Data(int ii) : i(ii) {} | ||
| }; | ||
|
|
||
| constexpr bool test() { | ||
| // convert the value | ||
| { | ||
| const std::expected<int, int> e1(5); | ||
| std::expected<Data, int> 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<int, int> e1(std::unexpect, 5); | ||
| std::expected<int, Data> 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<int, int> e1; | ||
| try { | ||
| [[maybe_unused]] std::expected<ThrowingInt, int> e2 = e1; | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| // throw on converting error | ||
| { | ||
| const std::expected<int, int> e1(std::unexpect); | ||
| try { | ||
| [[maybe_unused]] std::expected<int, ThrowingInt> e2 = e1; | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class U, class G> | ||
| // constexpr explicit(see below) expected(expected<U, G>&&); | ||
| // | ||
| // Let: | ||
| // - UF be const U | ||
| // - GF be const G | ||
| // | ||
| // Constraints: | ||
| // - is_constructible_v<T, UF> is true; and | ||
| // - is_constructible_v<E, GF> is true; and | ||
| // - is_constructible_v<T, expected<U, G>&> is false; and | ||
| // - is_constructible_v<T, expected<U, G>> is false; and | ||
| // - is_constructible_v<T, const expected<U, G>&> is false; and | ||
| // - is_constructible_v<T, const expected<U, G>> is false; and | ||
| // - is_convertible_v<expected<U, G>&, T> is false; and | ||
| // - is_convertible_v<expected<U, G>&&, T> is false; and | ||
| // - is_convertible_v<const expected<U, G>&, T> is false; and | ||
| // - is_convertible_v<const expected<U, G>&&, T> is false; and | ||
| // - is_constructible_v<unexpected<E>, expected<U, G>&> is false; and | ||
| // - is_constructible_v<unexpected<E>, expected<U, G>> is false; and | ||
| // - is_constructible_v<unexpected<E>, const expected<U, G>&> is false; and | ||
| // - is_constructible_v<unexpected<E>, const expected<U, G>> is false. | ||
| // | ||
| // Effects: If rhs.has_value(), direct-non-list-initializes val with std::forward<UF>(*rhs). Otherwise, direct-non-list-initializes unex with std::forward<GF>(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<UF, T> || !is_convertible_v<GF, E>. | ||
|
|
||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints: | ||
| template <class T1, class Err1, class T2, class Err2> | ||
| concept canCstrFromExpected = std::is_constructible_v<std::expected<T1, Err1>, std::expected<T2, Err2>&&>; | ||
|
|
||
| struct CtorFromInt { | ||
| CtorFromInt(int); | ||
| }; | ||
|
|
||
| static_assert(canCstrFromExpected<CtorFromInt, int, int, int>); | ||
|
|
||
| struct NoCtorFromInt {}; | ||
|
|
||
| // !is_constructible_v<T, UF> | ||
| static_assert(!canCstrFromExpected<NoCtorFromInt, int, int, int>); | ||
|
|
||
| // !is_constructible_v<E, GF> | ||
| static_assert(!canCstrFromExpected<int, NoCtorFromInt, int, int>); | ||
|
|
||
| template <class T> | ||
| struct CtorFrom { | ||
| explicit CtorFrom(int) | ||
| requires(!std::same_as<T, int>); | ||
| explicit CtorFrom(T); | ||
| explicit CtorFrom(auto&&) = delete; | ||
| }; | ||
|
|
||
| // is_constructible_v<T, expected<U, G>&> | ||
| static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int>&>, int, int, int>); | ||
|
|
||
| // is_constructible_v<T, expected<U, G>> | ||
| // note that this is true because it is covered by the other overload | ||
| // template<class U = T> 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<CtorFrom<std::expected<int, int>&&>, int, int, int>); | ||
|
|
||
| // is_constructible_v<T, expected<U, G>&> | ||
| static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int> const&>, int, int, int>); | ||
|
|
||
| // is_constructible_v<T, expected<U, G>> | ||
| static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int> const&&>, int, int, int>); | ||
|
|
||
| template <class T> | ||
| struct ConvertFrom { | ||
| ConvertFrom(int) | ||
| requires(!std::same_as<T, int>); | ||
| ConvertFrom(T); | ||
| ConvertFrom(auto&&) = delete; | ||
| }; | ||
|
|
||
| // is_convertible_v<expected<U, G>&, T> | ||
| static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int>&>, int, int, int>); | ||
|
|
||
| // is_convertible_v<expected<U, G>&&, T> | ||
| // note that this is true because it is covered by the other overload | ||
| // template<class U = T> 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<ConvertFrom<std::expected<int, int>&&>, int, int, int>); | ||
|
|
||
| // is_convertible_v<const expected<U, G>&, T> | ||
| static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int> const&>, int, int, int>); | ||
|
|
||
| // is_convertible_v<const expected<U, G>&&, T> | ||
| static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int> const&&>, int, int, int>); | ||
|
|
||
| // is_constructible_v<unexpected<E>, expected<U, G>&> | ||
| static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&>, int, int>); | ||
|
|
||
| // is_constructible_v<unexpected<E>, expected<U, G>> | ||
| static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&&>, int, int>); | ||
|
|
||
| // is_constructible_v<unexpected<E>, const expected<U, G>&> is false | ||
| static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&>, int, int>); | ||
|
|
||
| // is_constructible_v<unexpected<E>, const expected<U, G>> | ||
| static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&&>, int, int>); | ||
|
|
||
| // test explicit | ||
| static_assert(std::is_convertible_v<std::expected<int, int>&&, std::expected<short, long>>); | ||
|
|
||
| // !is_convertible_v<UF, T> | ||
| static_assert(std::is_constructible_v<std::expected<CtorFrom<int>, int>, std::expected<int, int>&&>); | ||
| static_assert(!std::is_convertible_v<std::expected<int, int>&&, std::expected<CtorFrom<int>, int>>); | ||
|
|
||
| // !is_convertible_v<GF, E>. | ||
| static_assert(std::is_constructible_v<std::expected<int, CtorFrom<int>>, std::expected<int, int>&&>); | ||
| static_assert(!std::is_convertible_v<std::expected<int, int>&&, std::expected<int, CtorFrom<int>>>); | ||
|
|
||
| struct Data { | ||
| MoveOnly data; | ||
| constexpr Data(MoveOnly&& m) : data(std::move(m)) {} | ||
| }; | ||
|
|
||
| constexpr bool test() { | ||
| // convert the value | ||
| { | ||
| std::expected<MoveOnly, int> e1(5); | ||
| std::expected<Data, int> 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<int, MoveOnly> e1(std::unexpect, 5); | ||
| std::expected<int, Data> 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<int, int> e1; | ||
| try { | ||
| [[maybe_unused]] std::expected<ThrowingInt, int> e2 = e1; | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| // throw on converting error | ||
| { | ||
| const std::expected<int, int> e1(std::unexpect); | ||
| try { | ||
| [[maybe_unused]] std::expected<int, ThrowingInt> e2 = e1; | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<T> is true and | ||
| // - is_copy_constructible_v<E> is true. | ||
| // | ||
| // This constructor is trivial if | ||
| // - is_trivially_copy_constructible_v<T> is true and | ||
| // - is_trivially_copy_constructible_v<E> is true. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #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<T> is true and | ||
| // - is_copy_constructible_v<E> is true. | ||
| static_assert(std::is_copy_constructible_v<std::expected<int, int>>); | ||
| static_assert(std::is_copy_constructible_v<std::expected<CopyableNonTrivial, int>>); | ||
| static_assert(std::is_copy_constructible_v<std::expected<int, CopyableNonTrivial>>); | ||
| static_assert(std::is_copy_constructible_v<std::expected<CopyableNonTrivial, CopyableNonTrivial>>); | ||
| static_assert(!std::is_copy_constructible_v<std::expected<NonCopyable, int>>); | ||
| static_assert(!std::is_copy_constructible_v<std::expected<int, NonCopyable>>); | ||
| static_assert(!std::is_copy_constructible_v<std::expected<NonCopyable, NonCopyable>>); | ||
|
|
||
| // Test: This constructor is trivial if | ||
| // - is_trivially_copy_constructible_v<T> is true and | ||
| // - is_trivially_copy_constructible_v<E> is true. | ||
| #if __cpp_concepts >= 202002 | ||
| static_assert(std::is_trivially_copy_constructible_v<std::expected<int, int>>); | ||
| #endif | ||
| static_assert(!std::is_trivially_copy_constructible_v<std::expected<CopyableNonTrivial, int>>); | ||
| static_assert(!std::is_trivially_copy_constructible_v<std::expected<int, CopyableNonTrivial>>); | ||
| static_assert(!std::is_trivially_copy_constructible_v<std::expected<CopyableNonTrivial, CopyableNonTrivial>>); | ||
|
|
||
| constexpr bool test() { | ||
| // copy the value non-trivial | ||
| { | ||
| const std::expected<CopyableNonTrivial, int> e1(5); | ||
| auto e2 = e1; | ||
| assert(e2.has_value()); | ||
| assert(e2.value().i == 5); | ||
| } | ||
|
|
||
| // copy the error non-trivial | ||
| { | ||
| const std::expected<int, CopyableNonTrivial> e1(std::unexpect, 5); | ||
| auto e2 = e1; | ||
| assert(!e2.has_value()); | ||
| assert(e2.error().i == 5); | ||
| } | ||
|
|
||
| // copy the value trivial | ||
| { | ||
| const std::expected<int, int> e1(5); | ||
| auto e2 = e1; | ||
| assert(e2.has_value()); | ||
| assert(e2.value() == 5); | ||
| } | ||
|
|
||
| // copy the error trivial | ||
| { | ||
| const std::expected<int, int> 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<Throwing, int> e1; | ||
| try { | ||
| [[maybe_unused]] auto e2 = e1; | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| // throw on copying error | ||
| { | ||
| const std::expected<int, Throwing> e1(std::unexpect); | ||
| try { | ||
| [[maybe_unused]] auto e2 = e1; | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<T> is true. | ||
| // | ||
| // Effects: Value-initializes val. | ||
| // Postconditions: has_value() is true. | ||
| // | ||
| // Throws: Any exception thrown by the initialization of val. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| struct NoDedefaultCtor { | ||
| NoDedefaultCtor() = delete; | ||
| }; | ||
|
|
||
| // Test constraints | ||
| static_assert(std::is_default_constructible_v<std::expected<int, int>>); | ||
| static_assert(!std::is_default_constructible_v<std::expected<NoDedefaultCtor, int>>); | ||
|
|
||
| struct MyInt { | ||
| int i; | ||
| friend constexpr bool operator==(const MyInt&, const MyInt&) = default; | ||
| }; | ||
|
|
||
| template <class T, class E> | ||
| constexpr void testDefaultCtor() { | ||
| std::expected<T, E> e; | ||
| assert(e.has_value()); | ||
| assert(e.value() == T()); | ||
| } | ||
|
|
||
| template <class T> | ||
| constexpr void testTypes() { | ||
| testDefaultCtor<T, int>(); | ||
| testDefaultCtor<T, NoDedefaultCtor>(); | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| testTypes<int>(); | ||
| testTypes<MyInt>(); | ||
| return true; | ||
| } | ||
|
|
||
| void testException() { | ||
| #ifndef TEST_HAS_NO_EXCEPTIONS | ||
| struct Except {}; | ||
|
|
||
| struct Throwing { | ||
| Throwing() { throw Except{}; }; | ||
| }; | ||
|
|
||
| try { | ||
| std::expected<Throwing, int> u; | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class... Args> | ||
| // constexpr explicit expected(in_place_t, Args&&... args); | ||
| // | ||
| // Constraints: is_constructible_v<T, Args...> is true. | ||
| // | ||
| // Effects: Direct-non-list-initializes val with std::forward<Args>(args).... | ||
| // | ||
| // Postconditions: has_value() is true. | ||
| // | ||
| // Throws: Any exception thrown by the initialization of val. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <tuple> | ||
| #include <utility> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints: | ||
| static_assert(std::is_constructible_v<std::expected<int, int>, std::in_place_t>); | ||
| static_assert(std::is_constructible_v<std::expected<int, int>, std::in_place_t, int>); | ||
|
|
||
| // !is_constructible_v<T, Args...> | ||
| struct foo {}; | ||
| static_assert(!std::is_constructible_v<std::expected<foo, int>, std::in_place_t, int>); | ||
|
|
||
| // test explicit | ||
| template <class T> | ||
| void conversion_test(T); | ||
|
|
||
| template <class T, class... Args> | ||
| concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); }; | ||
| static_assert(ImplicitlyConstructible<int, int>); | ||
|
|
||
| static_assert(!ImplicitlyConstructible<std::expected<int, int>, std::in_place_t>); | ||
| static_assert(!ImplicitlyConstructible<std::expected<int, int>, 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 <class T> | ||
| constexpr void testInt() { | ||
| std::expected<T, int> e(std::in_place, 5); | ||
| assert(e.has_value()); | ||
| assert(e.value() == 5); | ||
| } | ||
|
|
||
| template <class T> | ||
| constexpr void testLValue() { | ||
| T t(5); | ||
| std::expected<T, int> e(std::in_place, t); | ||
| assert(e.has_value()); | ||
| assert(e.value() == 5); | ||
| } | ||
|
|
||
| template <class T> | ||
| constexpr void testRValue() { | ||
| std::expected<T, int> e(std::in_place, T(5)); | ||
| assert(e.has_value()); | ||
| assert(e.value() == 5); | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| testInt<int>(); | ||
| testInt<CopyOnly>(); | ||
| testInt<MoveOnly>(); | ||
| testLValue<int>(); | ||
| testLValue<CopyOnly>(); | ||
| testRValue<int>(); | ||
| testRValue<MoveOnly>(); | ||
|
|
||
| // no arg | ||
| { | ||
| std::expected<int, int> e(std::in_place); | ||
| assert(e.has_value()); | ||
| assert(e.value() == 0); | ||
| } | ||
|
|
||
| // one arg | ||
| { | ||
| std::expected<int, int> e(std::in_place, 5); | ||
| assert(e.has_value()); | ||
| assert(e.value() == 5); | ||
| } | ||
|
|
||
| // multi args | ||
| { | ||
| std::expected<std::tuple<int, short, MoveOnly>, int> e(std::in_place, 1, 2, MoveOnly(3)); | ||
| assert(e.has_value()); | ||
| assert((e.value() == std::tuple<int, short, MoveOnly>(1, 2, MoveOnly(3)))); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| void testException() { | ||
| #ifndef TEST_HAS_NO_EXCEPTIONS | ||
| struct Except {}; | ||
|
|
||
| struct Throwing { | ||
| Throwing(int) { throw Except{}; }; | ||
| }; | ||
|
|
||
| try { | ||
| std::expected<Throwing, int> u(std::in_place, 5); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class U, class... Args> | ||
| // constexpr explicit expected(in_place_t, initializer_list<U> il, Args&&... args); | ||
| // | ||
| // Constraints: is_constructible_v<T, initializer_list<U>&, Args...> is true. | ||
| // | ||
| // Effects: Direct-non-list-initializes val with il, std::forward<Args>(args).... | ||
| // | ||
| // Postconditions: has_value() is true. | ||
| // | ||
| // Throws: Any exception thrown by the initialization of val. | ||
|
|
||
| #include <algorithm> | ||
| #include <cassert> | ||
| #include <expected> | ||
| #include <tuple> | ||
| #include <type_traits> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints: | ||
| static_assert( | ||
| std::is_constructible_v<std::expected<std::vector<int>, int>, std::in_place_t, std::initializer_list<int>>); | ||
|
|
||
| // !is_constructible_v<T, initializer_list<U>&, Args...> | ||
| static_assert(!std::is_constructible_v<std::expected<int, int>, std::in_place_t, std::initializer_list<int>>); | ||
|
|
||
| // test explicit | ||
| template <class T> | ||
| void conversion_test(T); | ||
|
|
||
| template <class T, class... Args> | ||
| concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); }; | ||
| static_assert(ImplicitlyConstructible<int, int>); | ||
|
|
||
| static_assert( | ||
| !ImplicitlyConstructible<std::expected<std::vector<int>, int>, std::in_place_t, std::initializer_list<int>>); | ||
|
|
||
| template <class... Ts> | ||
| struct Data { | ||
| std::vector<int> vec_; | ||
| std::tuple<Ts...> tuple_; | ||
|
|
||
| template <class... Us> | ||
| requires std::is_constructible_v<std::tuple<Ts...>, Us&&...> | ||
| constexpr Data(std::initializer_list<int> il, Us&&... us) : vec_(il), tuple_(std::forward<Us>(us)...) {} | ||
| }; | ||
|
|
||
| constexpr bool test() { | ||
| // no arg | ||
| { | ||
| std::expected<Data<>, 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<Data<MoveOnly>, 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<Data<int&, int&&, MoveOnly>, 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>, int) { throw Except{}; }; | ||
| }; | ||
|
|
||
| try { | ||
| std::expected<Throwing, int> u(std::in_place, {1, 2}, 5); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<T> is true and | ||
| // - is_move_constructible_v<E> 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<T> && is_nothrow_move_constructible_v<E>. | ||
| // | ||
| // This constructor is trivial if | ||
| // - is_trivially_move_constructible_v<T> is true and | ||
| // - is_trivially_move_constructible_v<E> is true. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #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<T> is true and | ||
| // - is_move_constructible_v<E> is true. | ||
| static_assert(std::is_move_constructible_v<std::expected<int, int>>); | ||
| static_assert(std::is_move_constructible_v<std::expected<MovableNonTrivial, int>>); | ||
| static_assert(std::is_move_constructible_v<std::expected<int, MovableNonTrivial>>); | ||
| static_assert(std::is_move_constructible_v<std::expected<MovableNonTrivial, MovableNonTrivial>>); | ||
| static_assert(!std::is_move_constructible_v<std::expected<NonMovable, int>>); | ||
| static_assert(!std::is_move_constructible_v<std::expected<int, NonMovable>>); | ||
| static_assert(!std::is_move_constructible_v<std::expected<NonMovable, NonMovable>>); | ||
|
|
||
| // Test: This constructor is trivial if | ||
| // - is_trivially_move_constructible_v<T> is true and | ||
| // - is_trivially_move_constructible_v<E> is true. | ||
| #if __cpp_concepts >= 202002 | ||
| static_assert(std::is_trivially_move_constructible_v<std::expected<int, int>>); | ||
| #endif | ||
| static_assert(!std::is_trivially_move_constructible_v<std::expected<MovableNonTrivial, int>>); | ||
| static_assert(!std::is_trivially_move_constructible_v<std::expected<int, MovableNonTrivial>>); | ||
| static_assert(!std::is_trivially_move_constructible_v<std::expected<MovableNonTrivial, MovableNonTrivial>>); | ||
|
|
||
| // Test: The exception specification is equivalent to | ||
| // is_nothrow_move_constructible_v<T> && is_nothrow_move_constructible_v<E>. | ||
| static_assert(std::is_nothrow_move_constructible_v<std::expected<int, int>>); | ||
| static_assert(!std::is_nothrow_move_constructible_v<std::expected<MoveMayThrow, int>>); | ||
| static_assert(!std::is_nothrow_move_constructible_v<std::expected<int, MoveMayThrow>>); | ||
| static_assert(!std::is_nothrow_move_constructible_v<std::expected<MoveMayThrow, MoveMayThrow>>); | ||
|
|
||
| constexpr bool test() { | ||
| // move the value non-trivial | ||
| { | ||
| std::expected<MovableNonTrivial, int> 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<int, MovableNonTrivial> 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<int, int> 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<int, int> 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<Throwing, int> e1; | ||
| try { | ||
| [[maybe_unused]] auto e2 = std::move(e1); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| // throw on moving error | ||
| { | ||
| std::expected<int, Throwing> e1(std::unexpect); | ||
| try { | ||
| [[maybe_unused]] auto e2 = std::move(e1); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
|
|
||
| // template<class U = T> | ||
| // constexpr explicit(!is_convertible_v<U, T>) expected(U&& v); | ||
| // | ||
| // Constraints: | ||
| // - is_same_v<remove_cvref_t<U>, in_place_t> is false; and | ||
| // - is_same_v<expected, remove_cvref_t<U>> is false; and | ||
| // - remove_cvref_t<U> is not a specialization of unexpected; and | ||
| // - is_constructible_v<T, U> is true. | ||
| // | ||
| // Effects: Direct-non-list-initializes val with std::forward<U>(v). | ||
| // | ||
| // Postconditions: has_value() is true. | ||
| // | ||
| // Throws: Any exception thrown by the initialization of val. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints: | ||
| static_assert(std::is_constructible_v<std::expected<int, int>, int>); | ||
|
|
||
| // is_same_v<remove_cvref_t<U>, in_place_t> | ||
| struct FromJustInplace { | ||
| FromJustInplace(std::in_place_t); | ||
| }; | ||
| static_assert(!std::is_constructible_v<std::expected<FromJustInplace, int>, std::in_place_t>); | ||
| static_assert(!std::is_constructible_v<std::expected<FromJustInplace, int>, std::in_place_t const&>); | ||
|
|
||
| // is_same_v<expected, remove_cvref_t<U>> | ||
| // Note that result is true because it is covered by the constructors that take expected | ||
| static_assert(std::is_constructible_v<std::expected<int, int>, std::expected<int, int>&>); | ||
|
|
||
| // remove_cvref_t<U> 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::expected<int, int>, std::unexpected<int>&>); | ||
|
|
||
| // !is_constructible_v<T, U> | ||
| struct foo {}; | ||
| static_assert(!std::is_constructible_v<std::expected<int, int>, foo>); | ||
|
|
||
| // test explicit(!is_convertible_v<U, T>) | ||
| struct NotConvertible { | ||
| explicit NotConvertible(int); | ||
| }; | ||
| static_assert(std::is_convertible_v<int, std::expected<int, int>>); | ||
| static_assert(!std::is_convertible_v<int, std::expected<NotConvertible, 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 <class T> | ||
| constexpr void testInt() { | ||
| std::expected<T, int> e(5); | ||
| assert(e.has_value()); | ||
| assert(e.value() == 5); | ||
| } | ||
|
|
||
| template <class T> | ||
| constexpr void testLValue() { | ||
| T t(5); | ||
| std::expected<T, int> e(t); | ||
| assert(e.has_value()); | ||
| assert(e.value() == 5); | ||
| } | ||
|
|
||
| template <class T> | ||
| constexpr void testRValue() { | ||
| std::expected<T, int> e(T(5)); | ||
| assert(e.has_value()); | ||
| assert(e.value() == 5); | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| testInt<int>(); | ||
| testInt<CopyOnly>(); | ||
| testInt<MoveOnly>(); | ||
| testLValue<int>(); | ||
| testLValue<CopyOnly>(); | ||
| testRValue<int>(); | ||
| testRValue<MoveOnly>(); | ||
|
|
||
| // 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<Bar, int> 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 | ||
| // see https://cplusplus.github.io/LWG/issue3836 | ||
| { | ||
| struct BaseError {}; | ||
| struct DerivedError : BaseError {}; | ||
|
|
||
| std::expected<bool, DerivedError> e1(false); | ||
| std::expected<bool, BaseError> 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<Throwing, int> u(5); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class... Args> | ||
| // constexpr explicit expected(unexpect_t, Args&&... args); | ||
| // | ||
| // Constraints: is_constructible_v<E, Args...> is true. | ||
| // | ||
| // Effects: Direct-non-list-initializes unex with std::forward<Args>(args).... | ||
| // | ||
| // Postconditions: has_value() is false. | ||
| // | ||
| // Throws: Any exception thrown by the initialization of unex. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <tuple> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints: | ||
| static_assert(std::is_constructible_v<std::expected<int, int>, std::unexpect_t>); | ||
| static_assert(std::is_constructible_v<std::expected<int, int>, std::unexpect_t, int>); | ||
|
|
||
| // !is_constructible_v<T, Args...> | ||
| struct foo {}; | ||
| static_assert(!std::is_constructible_v<std::expected<int, foo>, std::unexpect_t, int>); | ||
|
|
||
| // test explicit | ||
| template <class T> | ||
| void conversion_test(T); | ||
|
|
||
| template <class T, class... Args> | ||
| concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); }; | ||
| static_assert(ImplicitlyConstructible<int, int>); | ||
|
|
||
| static_assert(!ImplicitlyConstructible<std::expected<int, int>, std::unexpect_t>); | ||
| static_assert(!ImplicitlyConstructible<std::expected<int, int>, 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 <class T> | ||
| constexpr void testInt() { | ||
| std::expected<int, T> e(std::unexpect, 5); | ||
| assert(!e.has_value()); | ||
| assert(e.error() == 5); | ||
| } | ||
|
|
||
| template <class T> | ||
| constexpr void testLValue() { | ||
| T t(5); | ||
| std::expected<int, T> e(std::unexpect, t); | ||
| assert(!e.has_value()); | ||
| assert(e.error() == 5); | ||
| } | ||
|
|
||
| template <class T> | ||
| constexpr void testRValue() { | ||
| std::expected<int, T> e(std::unexpect, T(5)); | ||
| assert(!e.has_value()); | ||
| assert(e.error() == 5); | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| testInt<int>(); | ||
| testInt<CopyOnly>(); | ||
| testInt<MoveOnly>(); | ||
| testLValue<int>(); | ||
| testLValue<CopyOnly>(); | ||
| testRValue<int>(); | ||
| testRValue<MoveOnly>(); | ||
|
|
||
| // no arg | ||
| { | ||
| std::expected<int, int> e(std::unexpect); | ||
| assert(!e.has_value()); | ||
| assert(e.error() == 0); | ||
| } | ||
|
|
||
| // one arg | ||
| { | ||
| std::expected<int, int> e(std::unexpect, 5); | ||
| assert(!e.has_value()); | ||
| assert(e.error() == 5); | ||
| } | ||
|
|
||
| // multi args | ||
| { | ||
| std::expected<int, std::tuple<int, short, MoveOnly>> e(std::unexpect, 1, 2, MoveOnly(3)); | ||
| assert(!e.has_value()); | ||
| assert((e.error() == std::tuple<int, short, MoveOnly>(1, 2, MoveOnly(3)))); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| void testException() { | ||
| #ifndef TEST_HAS_NO_EXCEPTIONS | ||
| struct Except {}; | ||
|
|
||
| struct Throwing { | ||
| Throwing(int) { throw Except{}; }; | ||
| }; | ||
|
|
||
| try { | ||
| std::expected<int, Throwing> u(std::unexpect, 5); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class U, class... Args> | ||
| // constexpr explicit expected(unexpect_t, initializer_list<U> il, Args&&... args); | ||
| // | ||
| // Constraints: is_constructible_v<E, initializer_list<U>&, Args...> is true. | ||
| // | ||
| // Effects: Direct-non-list-initializes unex with il, std::forward<Args>(args).... | ||
| // | ||
| // Postconditions: has_value() is false. | ||
| // | ||
| // Throws: Any exception thrown by the initialization of unex. | ||
|
|
||
| #include <algorithm> | ||
| #include <cassert> | ||
| #include <expected> | ||
| #include <tuple> | ||
| #include <type_traits> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints: | ||
| static_assert( | ||
| std::is_constructible_v<std::expected<int, std::vector<int>>, std::unexpect_t, std::initializer_list<int>>); | ||
|
|
||
| // !is_constructible_v<T, initializer_list<U>&, Args...> | ||
| static_assert(!std::is_constructible_v<std::expected<int, int>, std::unexpect_t, std::initializer_list<int>>); | ||
|
|
||
| // test explicit | ||
| template <class T> | ||
| void conversion_test(T); | ||
|
|
||
| template <class T, class... Args> | ||
| concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); }; | ||
| static_assert(ImplicitlyConstructible<int, int>); | ||
|
|
||
| static_assert( | ||
| !ImplicitlyConstructible<std::expected<int, std::vector<int>>, std::unexpect_t, std::initializer_list<int>>); | ||
|
|
||
| template <class... Ts> | ||
| struct Data { | ||
| std::vector<int> vec_; | ||
| std::tuple<Ts...> tuple_; | ||
|
|
||
| template <class... Us> | ||
| requires std::is_constructible_v<std::tuple<Ts...>, Us&&...> | ||
| constexpr Data(std::initializer_list<int> il, Us&&... us) : vec_(il), tuple_(std::forward<Us>(us)...) {} | ||
| }; | ||
|
|
||
| constexpr bool test() { | ||
| // no arg | ||
| { | ||
| std::expected<int, Data<>> 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<int, Data<MoveOnly>> 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<int, Data<int&, int&&, MoveOnly>> 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>, int) { throw Except{}; }; | ||
| }; | ||
|
|
||
| try { | ||
| std::expected<int, Throwing> u(std::unexpect, {1, 2}, 5); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class G> | ||
| // constexpr explicit(!is_convertible_v<const G&, E>) expected(const unexpected<G>& e); | ||
| // | ||
| // Let GF be const G& | ||
| // | ||
| // Constraints: is_constructible_v<E, GF> is true. | ||
| // | ||
| // Effects: Direct-non-list-initializes unex with std::forward<GF>(e.error()). | ||
| // | ||
| // Postconditions: has_value() is false. | ||
| // | ||
| // Throws: Any exception thrown by the initialization of unex. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints | ||
| static_assert(std::is_constructible_v<std::expected<int, int>, const std::unexpected<int>&>); | ||
|
|
||
| // !is_constructible_v<E, GF> | ||
| struct foo {}; | ||
| static_assert(!std::is_constructible_v<std::expected<int, int>, const std::unexpected<foo>&>); | ||
| static_assert(!std::is_constructible_v<std::expected<int, MoveOnly>, const std::unexpected<MoveOnly>&>); | ||
|
|
||
| // explicit(!is_convertible_v<const G&, E>) | ||
| struct NotConvertible { | ||
| explicit NotConvertible(int); | ||
| }; | ||
| static_assert(std::is_convertible_v<const std::unexpected<int>&, std::expected<int, int>>); | ||
| static_assert(!std::is_convertible_v<const std::unexpected<int>&, std::expected<int, NotConvertible>>); | ||
|
|
||
| struct MyInt { | ||
| int i; | ||
| constexpr MyInt(int ii) : i(ii) {} | ||
| friend constexpr bool operator==(const MyInt&, const MyInt&) = default; | ||
| }; | ||
|
|
||
| template <class T> | ||
| constexpr void testUnexpected() { | ||
| const std::unexpected<int> u(5); | ||
| std::expected<int, T> e(u); | ||
| assert(!e.has_value()); | ||
| assert(e.error() == 5); | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| testUnexpected<int>(); | ||
| testUnexpected<MyInt>(); | ||
| return true; | ||
| } | ||
|
|
||
| void testException() { | ||
| #ifndef TEST_HAS_NO_EXCEPTIONS | ||
| struct Except {}; | ||
|
|
||
| struct Throwing { | ||
| Throwing(int) { throw Except{}; } | ||
| }; | ||
|
|
||
| { | ||
| const std::unexpected<int> u(5); | ||
| try { | ||
| [[maybe_unused]] std::expected<int, Throwing> e(u); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class G> | ||
| // constexpr explicit(!is_convertible_v<G, E>) expected(unexpected<G>&& e); | ||
| // | ||
| // Let GF be G | ||
| // | ||
| // Constraints: is_constructible_v<E, GF> is true. | ||
| // | ||
| // Effects: Direct-non-list-initializes unex with std::forward<GF>(e.error()). | ||
| // | ||
| // Postconditions: has_value() is false. | ||
| // | ||
| // Throws: Any exception thrown by the initialization of unex. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints | ||
| static_assert(std::is_constructible_v<std::expected<int, int>, std::unexpected<int>>); | ||
| static_assert(std::is_constructible_v<std::expected<int, MoveOnly>, std::unexpected<MoveOnly>>); | ||
|
|
||
| // !is_constructible_v<E, GF> | ||
| struct foo {}; | ||
| static_assert(!std::is_constructible_v<std::expected<int, int>, std::unexpected<foo>>); | ||
|
|
||
| // explicit(!is_convertible_v<G, E>) | ||
| struct NotConvertible { | ||
| explicit NotConvertible(int); | ||
| }; | ||
| static_assert(std::is_convertible_v<std::unexpected<int>&&, std::expected<int, int>>); | ||
| static_assert(!std::is_convertible_v<std::unexpected<int>&&, std::expected<int, NotConvertible>>); | ||
|
|
||
| struct MyInt { | ||
| int i; | ||
| constexpr MyInt(int ii) : i(ii) {} | ||
| friend constexpr bool operator==(const MyInt&, const MyInt&) = default; | ||
| }; | ||
|
|
||
| template <class Err> | ||
| constexpr void testInt() { | ||
| std::unexpected<int> u(5); | ||
| std::expected<int, Err> e(std::move(u)); | ||
| assert(!e.has_value()); | ||
| assert(e.error() == 5); | ||
| } | ||
|
|
||
| constexpr void testMoveOnly() { | ||
| std::unexpected<MoveOnly> u(MoveOnly(5)); | ||
| std::expected<int, MoveOnly> e(std::move(u)); | ||
| assert(!e.has_value()); | ||
| assert(e.error() == 5); | ||
| assert(u.error() == 0); | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| testInt<int>(); | ||
| testInt<MyInt>(); | ||
| testInt<MoveOnly>(); | ||
| testMoveOnly(); | ||
| return true; | ||
| } | ||
|
|
||
| void testException() { | ||
| #ifndef TEST_HAS_NO_EXCEPTIONS | ||
| struct Except {}; | ||
|
|
||
| struct Throwing { | ||
| Throwing(int) { throw Except{}; } | ||
| }; | ||
|
|
||
| { | ||
| std::unexpected<int> u(5); | ||
| try { | ||
| [[maybe_unused]] std::expected<int, Throwing> e(std::move(u)); | ||
| assert(false); | ||
| } catch (Except) { | ||
| } | ||
| } | ||
|
|
||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<T> is true, and is_trivially_destructible_v<E> is true, | ||
| // then this destructor is a trivial destructor. | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| // Test Remarks: If is_trivially_destructible_v<T> is true, and is_trivially_destructible_v<E> is true, | ||
| // then this destructor is a trivial destructor. | ||
| struct NonTrivial { | ||
| ~NonTrivial() {} | ||
| }; | ||
|
|
||
| #if __cpp_concepts >= 202002 | ||
| static_assert(std::is_trivially_destructible_v<std::expected<int, int>>); | ||
| #endif | ||
| static_assert(!std::is_trivially_destructible_v<std::expected<NonTrivial, int>>); | ||
| static_assert(!std::is_trivially_destructible_v<std::expected<int, NonTrivial>>); | ||
| static_assert(!std::is_trivially_destructible_v<std::expected<NonTrivial, NonTrivial>>); | ||
|
|
||
| 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<TrackedDestroy, TrackedDestroy> e(std::in_place, valueDestroyed); } | ||
| assert(valueDestroyed); | ||
| } | ||
|
|
||
| // has error | ||
| { | ||
| bool errorDestroyed = false; | ||
| { [[maybe_unused]] std::expected<TrackedDestroy, TrackedDestroy> e(std::unexpect, errorDestroyed); } | ||
| assert(errorDestroyed); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class T2> friend constexpr bool operator==(const expected& x, const T2& v); | ||
|
|
||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #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<Data, int> e1(std::in_place, 5); | ||
| int i2 = 10; | ||
| int i3 = 5; | ||
| assert(e1 != i2); | ||
| assert(e1 == i3); | ||
| } | ||
|
|
||
| // !x.has_value() | ||
| { | ||
| const std::expected<Data, int> 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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class T2, class E2> requires (!is_void_v<T2>) | ||
| // friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y); | ||
|
|
||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| // Test constraint | ||
| template <class T1, class T2> | ||
| concept CanCompare = requires(T1 t1, T2 t2) { t1 == t2; }; | ||
|
|
||
| struct Foo{}; | ||
| static_assert(!CanCompare<Foo, Foo>); | ||
|
|
||
| static_assert(CanCompare<std::expected<int, int>, std::expected<int, int>>); | ||
| static_assert(CanCompare<std::expected<int, int>, std::expected<short, short>>); | ||
|
|
||
| // Note this is true because other overloads are unconstrained | ||
| static_assert(CanCompare<std::expected<int, int>, std::expected<void, int>>); | ||
|
|
||
| constexpr bool test() { | ||
| // x.has_value() && y.has_value() | ||
| { | ||
| const std::expected<int, int> e1(5); | ||
| const std::expected<int, int> e2(10); | ||
| const std::expected<int, int> e3(5); | ||
| assert(e1 != e2); | ||
| assert(e1 == e3); | ||
| } | ||
|
|
||
| // !x.has_value() && y.has_value() | ||
| { | ||
| const std::expected<int, int> e1(std::unexpect, 5); | ||
| const std::expected<int, int> e2(10); | ||
| const std::expected<int, int> e3(5); | ||
| assert(e1 != e2); | ||
| assert(e1 != e3); | ||
| } | ||
|
|
||
| // x.has_value() && !y.has_value() | ||
| { | ||
| const std::expected<int, int> e1(5); | ||
| const std::expected<int, int> e2(std::unexpect, 10); | ||
| const std::expected<int, int> e3(std::unexpect, 5); | ||
| assert(e1 != e2); | ||
| assert(e1 != e3); | ||
| } | ||
|
|
||
| // !x.has_value() && !y.has_value() | ||
| { | ||
| const std::expected<int, int> e1(std::unexpect, 5); | ||
| const std::expected<int, int> e2(std::unexpect, 10); | ||
| const std::expected<int, int> e3(std::unexpect, 5); | ||
| assert(e1 != e2); | ||
| assert(e1 == e3); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class E2> friend constexpr bool operator==(const expected& x, const unexpected<E2>& e); | ||
|
|
||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #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<Data, Data> e1(std::in_place, 5); | ||
| std::unexpected<int> un2(10); | ||
| std::unexpected<int> un3(5); | ||
| assert(e1 != un2); | ||
| assert(e1 != un3); | ||
| } | ||
|
|
||
| // !x.has_value() | ||
| { | ||
| const std::expected<Data, Data> e1(std::unexpect, 5); | ||
| std::unexpected<int> un2(10); | ||
| std::unexpected<int> un3(5); | ||
| assert(e1 != un2); | ||
| assert(e1 == un3); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| // Test noexcept | ||
| template <class T> | ||
| concept ArrowNoexcept = | ||
| requires(T t) { | ||
| { t.operator->() } noexcept; | ||
| }; | ||
|
|
||
| static_assert(!ArrowNoexcept<int>); | ||
|
|
||
| static_assert(ArrowNoexcept<std::expected<int, int>>); | ||
| static_assert(ArrowNoexcept<const std::expected<int, int>>); | ||
|
|
||
| constexpr bool test() { | ||
| // const | ||
| { | ||
| const std::expected<int, int> e(5); | ||
| std::same_as<const int*> decltype(auto) x = e.operator->(); | ||
| assert(x == &(e.value())); | ||
| assert(*x == 5); | ||
| } | ||
|
|
||
| // non-const | ||
| { | ||
| std::expected<int, int> e(5); | ||
| std::same_as<int*> decltype(auto) x = e.operator->(); | ||
| assert(x == &(e.value())); | ||
| assert(*x == 5); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| // Test noexcept | ||
| template <class T> | ||
| concept OpBoolNoexcept = | ||
| requires(T t) { | ||
| { static_cast<bool>(t) } noexcept; | ||
| }; | ||
|
|
||
| struct Foo {}; | ||
| static_assert(!OpBoolNoexcept<Foo>); | ||
|
|
||
| static_assert(OpBoolNoexcept<std::expected<int, int>>); | ||
| static_assert(OpBoolNoexcept<const std::expected<int, int>>); | ||
|
|
||
| // Test explicit | ||
| static_assert(!std::is_convertible_v<std::expected<int, int>, bool>); | ||
|
|
||
| constexpr bool test() { | ||
| // has_value | ||
| { | ||
| const std::expected<int, int> e(5); | ||
| assert(static_cast<bool>(e)); | ||
| } | ||
|
|
||
| // !has_value | ||
| { | ||
| const std::expected<int, int> e(std::unexpect, 5); | ||
| assert(!static_cast<bool>(e)); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| // Test noexcept | ||
| template <class T> | ||
| concept DerefNoexcept = | ||
| requires(T t) { | ||
| { std::forward<T>(t).operator*() } noexcept; | ||
| }; | ||
|
|
||
| static_assert(!DerefNoexcept<int>); | ||
|
|
||
| static_assert(DerefNoexcept<std::expected<int, int>&>); | ||
| static_assert(DerefNoexcept<const std::expected<int, int>&>); | ||
| static_assert(DerefNoexcept<std::expected<int, int>&&>); | ||
| static_assert(DerefNoexcept<const std::expected<int, int>&&>); | ||
|
|
||
| constexpr bool test() { | ||
| // non-const & | ||
| { | ||
| std::expected<int, int> e(5); | ||
| decltype(auto) x = *e; | ||
| static_assert(std::same_as<decltype(x), int&>); | ||
| assert(&x == &(e.value())); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // const & | ||
| { | ||
| const std::expected<int, int> e(5); | ||
| decltype(auto) x = *e; | ||
| static_assert(std::same_as<decltype(x), const int&>); | ||
| assert(&x == &(e.value())); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // non-const && | ||
| { | ||
| std::expected<int, int> e(5); | ||
| decltype(auto) x = *std::move(e); | ||
| static_assert(std::same_as<decltype(x), int&&>); | ||
| assert(&x == &(e.value())); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // const && | ||
| { | ||
| const std::expected<int, int> e(5); | ||
| decltype(auto) x = *std::move(e); | ||
| static_assert(std::same_as<decltype(x), const int&&>); | ||
| assert(&x == &(e.value())); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| // Test noexcept | ||
| template <class T> | ||
| concept ErrorNoexcept = | ||
| requires(T t) { | ||
| { std::forward<T>(t).error() } noexcept; | ||
| }; | ||
|
|
||
| static_assert(!ErrorNoexcept<int>); | ||
|
|
||
| static_assert(ErrorNoexcept<std::expected<int, int>&>); | ||
| static_assert(ErrorNoexcept<const std::expected<int, int>&>); | ||
| static_assert(ErrorNoexcept<std::expected<int, int>&&>); | ||
| static_assert(ErrorNoexcept<const std::expected<int, int>&&>); | ||
|
|
||
| constexpr bool test() { | ||
| // non-const & | ||
| { | ||
| std::expected<int, int> e(std::unexpect, 5); | ||
| decltype(auto) x = e.error(); | ||
| static_assert(std::same_as<decltype(x), int&>); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // const & | ||
| { | ||
| const std::expected<int, int> e(std::unexpect, 5); | ||
| decltype(auto) x = e.error(); | ||
| static_assert(std::same_as<decltype(x), const int&>); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // non-const && | ||
| { | ||
| std::expected<int, int> e(std::unexpect, 5); | ||
| decltype(auto) x = std::move(e).error(); | ||
| static_assert(std::same_as<decltype(x), int&&>); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // const && | ||
| { | ||
| const std::expected<int, int> e(std::unexpect, 5); | ||
| decltype(auto) x = std::move(e).error(); | ||
| static_assert(std::same_as<decltype(x), const int&&>); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| // Test noexcept | ||
| template <class T> | ||
| concept HasValueNoexcept = | ||
| requires(T t) { | ||
| { t.has_value() } noexcept; | ||
| }; | ||
|
|
||
| struct Foo {}; | ||
| static_assert(!HasValueNoexcept<Foo>); | ||
|
|
||
| static_assert(HasValueNoexcept<std::expected<int, int>>); | ||
| static_assert(HasValueNoexcept<const std::expected<int, int>>); | ||
|
|
||
| constexpr bool test() { | ||
| // has_value | ||
| { | ||
| const std::expected<int, int> e(5); | ||
| assert(e.has_value()); | ||
| } | ||
|
|
||
| // !has_value | ||
| { | ||
| const std::expected<int, int> e(std::unexpect, 5); | ||
| assert(!e.has_value()); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| constexpr bool test() { | ||
| // non-const & | ||
| { | ||
| std::expected<int, int> e(5); | ||
| decltype(auto) x = e.value(); | ||
| static_assert(std::same_as<decltype(x), int&>); | ||
| assert(&x == &(*e)); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // const & | ||
| { | ||
| const std::expected<int, int> e(5); | ||
| decltype(auto) x = e.value(); | ||
| static_assert(std::same_as<decltype(x), const int&>); | ||
| assert(&x == &(*e)); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // non-const && | ||
| { | ||
| std::expected<int, int> e(5); | ||
| decltype(auto) x = std::move(e).value(); | ||
| static_assert(std::same_as<decltype(x), int&&>); | ||
| assert(&x == &(*e)); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // const && | ||
| { | ||
| const std::expected<int, int> e(5); | ||
| decltype(auto) x = std::move(e).value(); | ||
| static_assert(std::same_as<decltype(x), const int&&>); | ||
| assert(&x == &(*e)); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| void testException() { | ||
| #ifndef TEST_HAS_NO_EXCEPTIONS | ||
|
|
||
| // int | ||
| { | ||
| const std::expected<int, int> e(std::unexpect, 5); | ||
| try { | ||
| e.value(); | ||
| assert(false); | ||
| } catch (const std::bad_expected_access<int>& ex) { | ||
| assert(ex.error() == 5); | ||
| } | ||
| } | ||
|
|
||
| // MoveOnly | ||
| { | ||
| std::expected<int, MoveOnly> e(std::unexpect, 5); | ||
| try { | ||
| std::move(e).value(); | ||
| assert(false); | ||
| } catch (const std::bad_expected_access<MoveOnly>& ex) { | ||
| assert(ex.error() == 5); | ||
| } | ||
| } | ||
|
|
||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class U> constexpr T value_or(U&& v) const &; | ||
| // template<class U> constexpr T value_or(U&& v) &&; | ||
|
|
||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "MoveOnly.h" | ||
| #include "test_macros.h" | ||
|
|
||
| constexpr bool test() { | ||
| // const &, has_value() | ||
| { | ||
| const std::expected<int, int> e(5); | ||
| std::same_as<int> decltype(auto) x = e.value_or(10); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // const &, !has_value() | ||
| { | ||
| const std::expected<int, int> e(std::unexpect, 5); | ||
| std::same_as<int> decltype(auto) x = e.value_or(10); | ||
| assert(x == 10); | ||
| } | ||
|
|
||
| // &&, has_value() | ||
| { | ||
| std::expected<MoveOnly, int> e(std::in_place, 5); | ||
| std::same_as<MoveOnly> decltype(auto) x = std::move(e).value_or(10); | ||
| assert(x == 5); | ||
| } | ||
|
|
||
| // &&, !has_value() | ||
| { | ||
| std::expected<MoveOnly, int> e(std::unexpect, 5); | ||
| std::same_as<MoveOnly> 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<int, int> e(std::unexpect, 5); | ||
| try { | ||
| e.value(); | ||
| assert(false); | ||
| } catch (const std::bad_expected_access<int>& ex) { | ||
| assert(ex.error() == 5); | ||
| } | ||
| } | ||
|
|
||
| // MoveOnly | ||
| { | ||
| std::expected<int, MoveOnly> e(std::unexpect, 5); | ||
| try { | ||
| std::move(e).value(); | ||
| assert(false); | ||
| } catch (const std::bad_expected_access<MoveOnly>& ex) { | ||
| assert(ex.error() == 5); | ||
| } | ||
| } | ||
|
|
||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,223 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // 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, clang-15, apple-clang-14 | ||
|
|
||
| // friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #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<std::expected<int, int>>); | ||
|
|
||
| // !is_swappable_v<T> | ||
| static_assert(!std::is_swappable_v<std::expected<NotSwappable, int>>); | ||
|
|
||
| // !is_swappable_v<E> | ||
| static_assert(!std::is_swappable_v<std::expected<int, NotSwappable>>); | ||
|
|
||
| struct NotMoveContructible { | ||
| NotMoveContructible(NotMoveContructible&&) = delete; | ||
| friend void swap(NotMoveContructible&, NotMoveContructible&) {} | ||
| }; | ||
|
|
||
| // !is_move_constructible_v<T> | ||
| static_assert(!std::is_swappable_v<std::expected<NotMoveContructible, int>>); | ||
|
|
||
| // !is_move_constructible_v<E> | ||
| static_assert(!std::is_swappable_v<std::expected<int, NotMoveContructible>>); | ||
|
|
||
| struct MoveMayThrow { | ||
| MoveMayThrow(MoveMayThrow&&) noexcept(false); | ||
| friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {} | ||
| }; | ||
|
|
||
| // !is_nothrow_move_constructible_v<T> && is_nothrow_move_constructible_v<E> | ||
| static_assert(std::is_swappable_v<std::expected<MoveMayThrow, int>>); | ||
|
|
||
| // is_nothrow_move_constructible_v<T> && !is_nothrow_move_constructible_v<E> | ||
| static_assert(std::is_swappable_v<std::expected<int, MoveMayThrow>>); | ||
|
|
||
| // !is_nothrow_move_constructible_v<T> && !is_nothrow_move_constructible_v<E> | ||
| static_assert(!std::is_swappable_v<std::expected<MoveMayThrow, MoveMayThrow>>); | ||
|
|
||
| // Test noexcept | ||
| static_assert(std::is_nothrow_swappable_v<std::expected<int, int>>); | ||
|
|
||
| // !is_nothrow_move_constructible_v<T> | ||
| static_assert(!std::is_nothrow_swappable_v<std::expected<MoveMayThrow, int>>); | ||
|
|
||
| // !is_nothrow_move_constructible_v<E> | ||
| static_assert(!std::is_nothrow_swappable_v<std::expected<int, MoveMayThrow>>); | ||
|
|
||
| struct SwapMayThrow { | ||
| friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {} | ||
| }; | ||
|
|
||
| // !is_nothrow_swappable_v<T> | ||
| static_assert(!std::is_nothrow_swappable_v<std::expected<SwapMayThrow, int>>); | ||
|
|
||
| // !is_nothrow_swappable_v<E> | ||
| static_assert(!std::is_nothrow_swappable_v<std::expected<int, SwapMayThrow>>); | ||
|
|
||
| constexpr bool test() { | ||
| // this->has_value() && rhs.has_value() | ||
| { | ||
| std::expected<ADLSwap, int> x(std::in_place, 5); | ||
| std::expected<ADLSwap, int> 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<int, ADLSwap> x(std::unexpect, 5); | ||
| std::expected<int, ADLSwap> 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<E> | ||
| { | ||
| std::expected<TrackedMove<true>, TrackedMove<true>> e1(std::in_place, 5); | ||
| std::expected<TrackedMove<true>, TrackedMove<true>> 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<E> | ||
| { | ||
| std::expected<TrackedMove<true>, TrackedMove<false>> e1(std::in_place, 5); | ||
| std::expected<TrackedMove<true>, TrackedMove<false>> 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<E> | ||
| { | ||
| std::expected<TrackedMove<true>, TrackedMove<true>> e1(std::unexpect, 10); | ||
| std::expected<TrackedMove<true>, TrackedMove<true>> 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<E> | ||
| { | ||
| std::expected<TrackedMove<true>, TrackedMove<false>> e1(std::unexpect, 10); | ||
| std::expected<TrackedMove<true>, TrackedMove<false>> 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<ThrowOnMoveConstruct, int> e1(std::unexpect, 5); | ||
| std::expected<ThrowOnMoveConstruct, int> 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<int, ThrowOnMoveConstruct> e1(5); | ||
| std::expected<int, ThrowOnMoveConstruct> e2(std::unexpect); | ||
| try { | ||
| swap(e1, e2); | ||
| assert(false); | ||
| } catch (Except) { | ||
| assert(e1.has_value()); | ||
| assert(*e1 == 5); | ||
| } | ||
| } | ||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<T> is true and | ||
| // is_swappable_v<E> is true and | ||
| // is_move_constructible_v<T> && is_move_constructible_v<E> is true, and | ||
| // is_nothrow_move_constructible_v<T> || is_nothrow_move_constructible_v<E> is true. | ||
| // | ||
| // Throws: Any exception thrown by the expressions in the Effects. | ||
| // Remarks: The exception specification is equivalent to: | ||
| // is_nothrow_move_constructible_v<T> && is_nothrow_swappable_v<T> && | ||
| // is_nothrow_move_constructible_v<E> && is_nothrow_swappable_v<E> | ||
|
|
||
| #include <cassert> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "../../types.h" | ||
| #include "test_macros.h" | ||
|
|
||
| // Test Constraints: | ||
| template <class T, class E> | ||
| concept HasMemberSwap = requires(std::expected<T, E> x, std::expected<T, E> y) { x.swap(y); }; | ||
|
|
||
| static_assert(HasMemberSwap<int, int>); | ||
|
|
||
| struct NotSwappable {}; | ||
| void swap(NotSwappable&, NotSwappable&) = delete; | ||
|
|
||
| // !is_swappable_v<T> | ||
| static_assert(!HasMemberSwap<NotSwappable, int>); | ||
|
|
||
| // !is_swappable_v<E> | ||
| static_assert(!HasMemberSwap<int, NotSwappable>); | ||
|
|
||
| struct NotMoveContructible { | ||
| NotMoveContructible(NotMoveContructible&&) = delete; | ||
| friend void swap(NotMoveContructible&, NotMoveContructible&) {} | ||
| }; | ||
|
|
||
| // !is_move_constructible_v<T> | ||
| static_assert(!HasMemberSwap<NotMoveContructible, int>); | ||
|
|
||
| // !is_move_constructible_v<E> | ||
| static_assert(!HasMemberSwap<int, NotMoveContructible>); | ||
|
|
||
| struct MoveMayThrow { | ||
| MoveMayThrow(MoveMayThrow&&) noexcept(false); | ||
| friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {} | ||
| }; | ||
|
|
||
| // !is_nothrow_move_constructible_v<T> && is_nothrow_move_constructible_v<E> | ||
| static_assert(HasMemberSwap<MoveMayThrow, int>); | ||
|
|
||
| // is_nothrow_move_constructible_v<T> && !is_nothrow_move_constructible_v<E> | ||
| static_assert(HasMemberSwap<int, MoveMayThrow>); | ||
|
|
||
| // !is_nothrow_move_constructible_v<T> && !is_nothrow_move_constructible_v<E> | ||
| static_assert(!HasMemberSwap<MoveMayThrow, MoveMayThrow>); | ||
|
|
||
| // Test noexcept | ||
| template <class T, class E> | ||
| concept MemberSwapNoexcept = | ||
| requires(std::expected<T, E> x, std::expected<T, E> y) { | ||
| { x.swap(y) } noexcept; | ||
| }; | ||
|
|
||
| static_assert(MemberSwapNoexcept<int, int>); | ||
|
|
||
| // !is_nothrow_move_constructible_v<T> | ||
| static_assert(!MemberSwapNoexcept<MoveMayThrow, int>); | ||
|
|
||
| // !is_nothrow_move_constructible_v<E> | ||
| static_assert(!MemberSwapNoexcept<int, MoveMayThrow>); | ||
|
|
||
| struct SwapMayThrow { | ||
| friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {} | ||
| }; | ||
|
|
||
| // !is_nothrow_swappable_v<T> | ||
| static_assert(!MemberSwapNoexcept<SwapMayThrow, int>); | ||
|
|
||
| // !is_nothrow_swappable_v<E> | ||
| static_assert(!MemberSwapNoexcept<int, SwapMayThrow>); | ||
|
|
||
| constexpr bool test() { | ||
| // this->has_value() && rhs.has_value() | ||
| { | ||
| std::expected<ADLSwap, int> x(std::in_place, 5); | ||
| std::expected<ADLSwap, int> 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<int, ADLSwap> x(std::unexpect, 5); | ||
| std::expected<int, ADLSwap> 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<E> | ||
| { | ||
| std::expected<TrackedMove<true>, TrackedMove<true>> e1(std::in_place, 5); | ||
| std::expected<TrackedMove<true>, TrackedMove<true>> 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<E> | ||
| { | ||
| std::expected<TrackedMove<true>, TrackedMove<false>> e1(std::in_place, 5); | ||
| std::expected<TrackedMove<true>, TrackedMove<false>> 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<E> | ||
| { | ||
| std::expected<TrackedMove<true>, TrackedMove<true>> e1(std::unexpect, 10); | ||
| std::expected<TrackedMove<true>, TrackedMove<true>> 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<E> | ||
| { | ||
| std::expected<TrackedMove<true>, TrackedMove<false>> e1(std::unexpect, 10); | ||
| std::expected<TrackedMove<true>, TrackedMove<false>> 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<ThrowOnMoveConstruct, int> e1(std::unexpect, 5); | ||
| std::expected<ThrowOnMoveConstruct, int> 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<int, ThrowOnMoveConstruct> e1(5); | ||
| std::expected<int, ThrowOnMoveConstruct> e2(std::unexpect); | ||
| try { | ||
| e1.swap(e2); | ||
| assert(false); | ||
| } catch (Except) { | ||
| assert(e1.has_value()); | ||
| assert(*e1 == 5); | ||
| } | ||
| } | ||
| #endif // TEST_HAS_NO_EXCEPTIONS | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| testException(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <expected> | ||
|
|
||
| struct Error { | ||
| int i; | ||
| constexpr Error(int ii) : i(ii) {} | ||
| }; | ||
|
|
||
| constexpr bool test() { | ||
| std::unexpected<Error> unex1(4); | ||
| const std::unexpected<Error> unex2(5); | ||
| unex1 = unex2; | ||
| assert(unex1.error().i == 5); | ||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <expected> | ||
| #include <utility> | ||
|
|
||
| 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<Error> unex1(4); | ||
| std::unexpected<Error> 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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<class E> unexpected(E) -> unexpected<E>; | ||
|
|
||
| #include <concepts> | ||
| #include <expected> | ||
|
|
||
| struct Foo{}; | ||
|
|
||
| static_assert(std::same_as<decltype(std::unexpected(5)), std::unexpected<int>>); | ||
| static_assert(std::same_as<decltype(std::unexpected(Foo{})), std::unexpected<Foo>>); | ||
| static_assert(std::same_as<decltype(std::unexpected(std::unexpected<int>(5))), std::unexpected<int>>); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <cassert> | ||
| #include <expected> | ||
|
|
||
| struct Error { | ||
| int i; | ||
| constexpr Error(int ii) : i(ii) {} | ||
| }; | ||
|
|
||
| constexpr bool test() { | ||
| const std::unexpected<Error> unex(5); | ||
| auto unex2 = unex; | ||
| assert(unex2.error().i == 5); | ||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
| return 0; | ||
| } |