brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.0 KiB · dea0e53 Raw
211 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(expected<U, G>&&);13//14// Let:15// - UF be const U16// - GF be const G17//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 "MoveOnly.h"49#include "test_macros.h"50#include "../../types.h"51 52// Test Constraints:53template <class T1, class Err1, class T2, class Err2>54concept canCstrFromExpected = std::is_constructible_v<std::expected<T1, Err1>, std::expected<T2, Err2>&&>;55 56struct CtorFromInt {57  CtorFromInt(int);58};59 60static_assert(canCstrFromExpected<CtorFromInt, int, int, int>);61 62struct NoCtorFromInt {};63 64// !is_constructible_v<T, UF>65static_assert(!canCstrFromExpected<NoCtorFromInt, int, int, int>);66 67// !is_constructible_v<E, GF>68static_assert(!canCstrFromExpected<int, NoCtorFromInt, int, int>);69 70template <class T>71struct CtorFrom {72  explicit CtorFrom(int)73    requires(!std::same_as<T, int>);74  explicit CtorFrom(T);75  explicit CtorFrom(auto&&) = delete;76};77 78// is_constructible_v<T, expected<U, G>&>79static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int>&>, int, int, int>);80 81// is_constructible_v<T, expected<U, G>>82// note that this is true because it is covered by the other overload83//   template<class U = T> constexpr explicit(see below) expected(U&& v);84// The fact that it is not ambiguous proves that the overload under testing is removed85static_assert(canCstrFromExpected<CtorFrom<std::expected<int, int>&&>, int, int, int>);86 87// is_constructible_v<T, expected<U, G>&>88static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int> const&>, int, int, int>);89 90// is_constructible_v<T, expected<U, G>>91static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int> const&&>, int, int, int>);92 93template <class T>94struct ConvertFrom {95  ConvertFrom(int)96    requires(!std::same_as<T, int>);97  ConvertFrom(T);98  ConvertFrom(auto&&) = delete;99};100 101// is_convertible_v<expected<U, G>&, T>102static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int>&>, int, int, int>);103 104// is_convertible_v<expected<U, G>&&, T>105// note that this is true because it is covered by the other overload106//   template<class U = T> constexpr explicit(see below) expected(U&& v);107// The fact that it is not ambiguous proves that the overload under testing is removed108static_assert(canCstrFromExpected<ConvertFrom<std::expected<int, int>&&>, int, int, int>);109 110// is_convertible_v<const expected<U, G>&, T>111static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int> const&>, int, int, int>);112 113// is_convertible_v<const expected<U, G>&&, T>114static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int> const&&>, int, int, int>);115 116// is_constructible_v<unexpected<E>, expected<U, G>&>117static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&>, int, int>);118 119// is_constructible_v<unexpected<E>, expected<U, G>>120static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&&>, int, int>);121 122// is_constructible_v<unexpected<E>, const expected<U, G>&> is false123static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&>, int, int>);124 125// is_constructible_v<unexpected<E>, const expected<U, G>>126static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&&>, int, int>);127 128// test explicit129static_assert(std::is_convertible_v<std::expected<int, int>&&, std::expected<short, long>>);130 131// !is_convertible_v<UF, T>132static_assert(std::is_constructible_v<std::expected<CtorFrom<int>, int>, std::expected<int, int>&&>);133static_assert(!std::is_convertible_v<std::expected<int, int>&&, std::expected<CtorFrom<int>, int>>);134 135// !is_convertible_v<GF, E>.136static_assert(std::is_constructible_v<std::expected<int, CtorFrom<int>>, std::expected<int, int>&&>);137static_assert(!std::is_convertible_v<std::expected<int, int>&&, std::expected<int, CtorFrom<int>>>);138 139struct Data {140  MoveOnly data;141  constexpr Data(MoveOnly&& m) : data(std::move(m)) {}142};143 144constexpr bool test() {145  // convert the value146  {147    std::expected<MoveOnly, int> e1(5);148    std::expected<Data, int> e2 = std::move(e1);149    assert(e2.has_value());150    assert(e2.value().data.get() == 5);151    assert(e1.has_value());152    assert(e1.value().get() == 0);153  }154 155  // convert the error156  {157    std::expected<int, MoveOnly> e1(std::unexpect, 5);158    std::expected<int, Data> e2 = std::move(e1);159    assert(!e2.has_value());160    assert(e2.error().data.get() == 5);161    assert(!e1.has_value());162    assert(e1.error().get() == 0);163  }164 165  // convert TailClobberer166  {167    std::expected<TailClobbererNonTrivialMove<0>, char> e1;168    std::expected<TailClobberer<0>, char> e2 = std::move(e1);169    assert(e2.has_value());170    assert(e1.has_value());171  }172 173  return true;174}175 176void testException() {177#ifndef TEST_HAS_NO_EXCEPTIONS178  struct ThrowingInt {179    ThrowingInt(int) { throw Except{}; }180  };181 182  // throw on converting value183  {184    const std::expected<int, int> e1;185    try {186      [[maybe_unused]] std::expected<ThrowingInt, int> e2 = e1;187      assert(false);188    } catch (Except) {189    }190  }191 192  // throw on converting error193  {194    const std::expected<int, int> e1(std::unexpect);195    try {196      [[maybe_unused]] std::expected<int, ThrowingInt> e2 = e1;197      assert(false);198    } catch (Except) {199    }200  }201 202#endif // TEST_HAS_NO_EXCEPTIONS203}204 205int main(int, char**) {206  test();207  static_assert(test());208  testException();209  return 0;210}211