brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · ac369a5 Raw
212 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2010 11//  template<class U, class G>12//    constexpr explicit(see below) expected(const expected<U, G>&);13//14// Let:15// - UF be const U&16// - GF be const G&17//18// Constraints:19// - is_constructible_v<T, UF> is true; and20// - is_constructible_v<E, GF> is true; and21// - is_constructible_v<T, expected<U, G>&> is false; and22// - is_constructible_v<T, expected<U, G>> is false; and23// - is_constructible_v<T, const expected<U, G>&> is false; and24// - is_constructible_v<T, const expected<U, G>> is false; and25// - is_convertible_v<expected<U, G>&, T> is false; and26// - is_convertible_v<expected<U, G>&&, T> is false; and27// - is_convertible_v<const expected<U, G>&, T> is false; and28// - is_convertible_v<const expected<U, G>&&, T> is false; and29// - is_constructible_v<unexpected<E>, expected<U, G>&> is false; and30// - is_constructible_v<unexpected<E>, expected<U, G>> is false; and31// - is_constructible_v<unexpected<E>, const expected<U, G>&> is false; and32// - is_constructible_v<unexpected<E>, const expected<U, G>> is false.33//34// 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()).35//36// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true.37//38// Throws: Any exception thrown by the initialization of val or unex.39//40// Remarks: The expression inside explicit is equivalent to !is_convertible_v<UF, T> || !is_convertible_v<GF, E>.41 42#include <cassert>43#include <concepts>44#include <expected>45#include <type_traits>46#include <utility>47 48#include "test_macros.h"49#include "../../types.h"50 51// Test Constraints:52template <class T1, class Err1, class T2, class Err2>53concept canCstrFromExpected = std::is_constructible_v<std::expected<T1, Err1>, const std::expected<T2, Err2>&>;54 55struct CtorFromInt {56  CtorFromInt(int);57};58 59static_assert(canCstrFromExpected<CtorFromInt, int, int, int>);60 61struct NoCtorFromInt {};62 63// !is_constructible_v<T, UF>64static_assert(!canCstrFromExpected<NoCtorFromInt, int, int, int>);65 66// !is_constructible_v<E, GF>67static_assert(!canCstrFromExpected<int, NoCtorFromInt, int, int>);68 69template <class T>70struct CtorFrom {71  explicit CtorFrom(int)72    requires(!std::same_as<T, int>);73  explicit CtorFrom(T);74  explicit CtorFrom(auto&&) = delete;75};76 77// is_constructible_v<T, expected<U, G>&>78static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int>&>, int, int, int>);79 80// is_constructible_v<T, expected<U, G>>81static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int>&&>, int, int, int>);82 83// is_constructible_v<T, expected<U, G>&>84// note that this is true because it is covered by the other overload85//   template<class U = T> constexpr explicit(see below) expected(U&& v);86// The fact that it is not ambiguous proves that the overload under testing is removed87static_assert(canCstrFromExpected<CtorFrom<std::expected<int, int> const&>, int, int, int>);88 89// is_constructible_v<T, expected<U, G>>90static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int> const&&>, int, int, int>);91 92template <class T>93struct ConvertFrom {94  ConvertFrom(int)95    requires(!std::same_as<T, int>);96  ConvertFrom(T);97  ConvertFrom(auto&&) = delete;98};99 100// is_convertible_v<expected<U, G>&, T>101static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int>&>, int, int, int>);102 103// is_convertible_v<expected<U, G>&&, T>104static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int>&&>, int, int, int>);105 106// is_convertible_v<const expected<U, G>&, T>107// note that this is true because it is covered by the other overload108//   template<class U = T> constexpr explicit(see below) expected(U&& v);109// The fact that it is not ambiguous proves that the overload under testing is removed110static_assert(canCstrFromExpected<ConvertFrom<std::expected<int, int> const&>, int, int, int>);111 112// is_convertible_v<const expected<U, G>&&, T>113static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int> const&&>, int, int, int>);114 115// Note for below 4 tests, because their E is constructible from cvref of std::expected<int, int>,116// unexpected<E> will be constructible from cvref of std::expected<int, int>117// is_constructible_v<unexpected<E>, expected<U, G>&>118static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&>, int, int>);119 120// is_constructible_v<unexpected<E>, expected<U, G>>121static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&&>, int, int>);122 123// is_constructible_v<unexpected<E>, const expected<U, G>&> is false124static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&>, int, int>);125 126// is_constructible_v<unexpected<E>, const expected<U, G>>127static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&&>, int, int>);128 129// test explicit130static_assert(std::is_convertible_v<const std::expected<int, int>&, std::expected<short, long>>);131 132// !is_convertible_v<UF, T>133static_assert(std::is_constructible_v<std::expected<CtorFrom<int>, int>, const std::expected<int, int>&>);134static_assert(!std::is_convertible_v<const std::expected<int, int>&, std::expected<CtorFrom<int>, int>>);135 136// !is_convertible_v<GF, E>.137static_assert(std::is_constructible_v<std::expected<int, CtorFrom<int>>, const std::expected<int, int>&>);138static_assert(!std::is_convertible_v<const std::expected<int, int>&, std::expected<int, CtorFrom<int>>>);139 140struct Data {141  int i;142  constexpr Data(int ii) : i(ii) {}143};144 145constexpr bool test() {146  // convert the value147  {148    const std::expected<int, int> e1(5);149    std::expected<Data, int> e2 = e1;150    assert(e2.has_value());151    assert(e2.value().i == 5);152    assert(e1.has_value());153    assert(e1.value() == 5);154  }155 156  // convert the error157  {158    const std::expected<int, int> e1(std::unexpect, 5);159    std::expected<int, Data> e2 = e1;160    assert(!e2.has_value());161    assert(e2.error().i == 5);162    assert(!e1.has_value());163    assert(e1.error() == 5);164  }165 166  // convert TailClobberer167  {168    const std::expected<TailClobbererNonTrivialMove<0>, char> e1;169    std::expected<TailClobberer<0>, char> e2 = e1;170    assert(e2.has_value());171    assert(e1.has_value());172  }173 174  return true;175}176 177void testException() {178#ifndef TEST_HAS_NO_EXCEPTIONS179  struct ThrowingInt {180    ThrowingInt(int) { throw Except{}; }181  };182 183  // throw on converting value184  {185    const std::expected<int, int> e1;186    try {187      [[maybe_unused]] std::expected<ThrowingInt, int> e2 = e1;188      assert(false);189    } catch (Except) {190    }191  }192 193  // throw on converting error194  {195    const std::expected<int, int> e1(std::unexpect);196    try {197      [[maybe_unused]] std::expected<int, ThrowingInt> e2 = e1;198      assert(false);199    } catch (Except) {200    }201  }202 203#endif // TEST_HAS_NO_EXCEPTIONS204}205 206int main(int, char**) {207  test();208  static_assert(test());209  testException();210  return 0;211}212