brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 31cecc1 Raw
215 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 G>12//   constexpr expected& operator=(unexpected<G>&& e);13//14// Let GF be G15// Constraints:16// - is_constructible_v<E, GF> is true; and17// - is_assignable_v<E&, GF> is true; and18// - is_nothrow_constructible_v<E, GF> || is_nothrow_move_constructible_v<T> ||19//   is_nothrow_move_constructible_v<E> is true.20//21// Effects:22// - If has_value() is true, equivalent to:23//   reinit-expected(unex, val, std::forward<GF>(e.error()));24//   has_val = false;25// - Otherwise, equivalent to: unex = std::forward<GF>(e.error());26// Returns: *this.27 28#include <cassert>29#include <concepts>30#include <expected>31#include <type_traits>32#include <utility>33 34#include "../../types.h"35#include "test_macros.h"36 37struct NotMoveConstructible {38  NotMoveConstructible(NotMoveConstructible&&)            = delete;39  NotMoveConstructible& operator=(NotMoveConstructible&&) = default;40};41 42struct NotMoveAssignable {43  NotMoveAssignable(NotMoveAssignable&&)            = default;44  NotMoveAssignable& operator=(NotMoveAssignable&&) = delete;45};46 47struct MoveMayThrow {48  MoveMayThrow(MoveMayThrow const&)            = default;49  MoveMayThrow& operator=(const MoveMayThrow&) = default;50  MoveMayThrow(MoveMayThrow&&) noexcept(false) {}51  MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; }52};53 54// Test constraints55static_assert(std::is_assignable_v<std::expected<int, int>&, std::unexpected<int>&&>);56 57// !is_constructible_v<E, GF>58static_assert(59    !std::is_assignable_v<std::expected<int, NotMoveConstructible>&, std::unexpected<NotMoveConstructible>&&>);60 61// !is_assignable_v<E&, GF>62static_assert(!std::is_assignable_v<std::expected<int, NotMoveAssignable>&, std::unexpected<NotMoveAssignable>&&>);63 64template <bool moveNoexcept, bool convertNoexcept>65struct MaybeNoexcept {66  explicit MaybeNoexcept(int) noexcept(convertNoexcept);67  MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept);68  MaybeNoexcept& operator=(MaybeNoexcept&&) = default;69  MaybeNoexcept& operator=(int);70};71 72// !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> &&73// is_nothrow_move_constructible_v<E>74static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<true, false>>&,75                                   std::unexpected<int>&&>);76 77// is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> &&78// !is_nothrow_move_constructible_v<E>79static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<false, true>>&,80                                   std::unexpected<int>&&>);81 82// !is_nothrow_constructible_v<E, GF> && is_nothrow_move_constructible_v<T> &&83// !is_nothrow_move_constructible_v<E>84static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<true, true>, MaybeNoexcept<false, false>>&,85                                   std::unexpected<int>&&>);86 87// !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> &&88// !is_nothrow_move_constructible_v<E>89static_assert(!std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<false, false>>&,90                                    std::unexpected<int>&&>);91 92constexpr bool test() {93  // - If has_value() is true, equivalent to:94  //   reinit-expected(unex, val, std::forward<GF>(e.error()));95  // is_nothrow_constructible_v<E, GF>96  //97  //  In this case, it should call the branch98  //    destroy_at(addressof(oldval));99  //    construct_at(addressof(newval), std::forward<Args>(args)...);100  {101    BothNoexcept::state oldState{};102    std::expected<BothNoexcept, BothNoexcept> e(std::in_place, oldState, 5);103    std::unexpected<int> un(10);104    decltype(auto) x = (e = std::move(un));105    static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, BothNoexcept>&>);106    assert(&x == &e);107 108    assert(!oldState.moveCtorCalled);109    assert(oldState.dtorCalled);110    assert(e.error().movedFromInt);111  }112 113  // - If has_value() is true, equivalent to:114  //   reinit-expected(unex, val, std::forward<GF>(e.error()));115  // !is_nothrow_constructible_v<E, GF> && is_nothrow_move_constructible_v<E>116  //117  //  In this case, it should call the branch118  //  T tmp(std::forward<Args>(args)...);119  //  destroy_at(addressof(oldval));120  //  construct_at(addressof(newval), std::move(tmp));121  {122    BothNoexcept::state oldState{};123    std::expected<BothNoexcept, MoveNoexceptConvThrow> e(std::in_place, oldState, 5);124    std::unexpected<int> un(10);125    decltype(auto) x = (e = std::move(un));126    static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, MoveNoexceptConvThrow>&>);127    assert(&x == &e);128 129    assert(!oldState.moveCtorCalled);130    assert(oldState.dtorCalled);131    assert(!e.error().movedFromInt);132    assert(e.error().movedFromTmp);133  }134 135  // - If has_value() is true, equivalent to:136  //   reinit-expected(unex, val, std::forward<GF>(e.error()));137  // !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<E>138  // is_nothrow_move_constructible_v<T>139  //140  //  In this case, it should call the branch141  //  U tmp(std::move(oldval));142  //  destroy_at(addressof(oldval));143  //  try {144  //    construct_at(addressof(newval), std::forward<Args>(args)...);145  //  } catch (...) {146  //    construct_at(addressof(oldval), std::move(tmp));147  //    throw;148  //  }149  {150    BothNoexcept::state oldState{};151    std::expected<BothNoexcept, BothMayThrow> e(std::in_place, oldState, 5);152    std::unexpected<int> un(10);153    decltype(auto) x = (e = std::move(un));154    static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, BothMayThrow>&>);155    assert(&x == &e);156 157    assert(oldState.moveCtorCalled);158    assert(oldState.dtorCalled);159    assert(e.error().movedFromInt);160  }161 162  // Otherwise, equivalent to: unex = std::forward<GF>(e.error());163  {164    Traced::state oldState{};165    Traced::state newState{};166    std::expected<int, Traced> e1(std::unexpect, oldState, 5);167    std::unexpected<Traced> e(std::in_place, newState, 10);168    decltype(auto) x = (e1 = std::move(e));169    static_assert(std::same_as<decltype(x), std::expected<int, Traced >&>);170    assert(&x == &e1);171 172    assert(!e1.has_value());173    assert(e1.error().data_ == 10);174    assert(oldState.moveAssignCalled);175  }176 177  // CheckForInvalidWrites178  {179    {180      CheckForInvalidWrites<true, true> e;181      std::unexpected<int> un(std::in_place, 42);182      e = std::move(un);183      assert(e.check());184    }185    {186      CheckForInvalidWrites<false, true> e;187      std::unexpected<bool> un(std::in_place, true);188      e = std::move(un);189      assert(e.check());190    }191  }192 193  return true;194}195 196void testException() {197#ifndef TEST_HAS_NO_EXCEPTIONS198  std::expected<void, ThrowOnMoveConstruct> e1(std::in_place);199  std::unexpected<ThrowOnMoveConstruct> un(std::in_place);200  try {201    e1 = std::move(un);202    assert(false);203  } catch (Except) {204    assert(e1.has_value());205  }206#endif // TEST_HAS_NO_EXCEPTIONS207}208 209int main(int, char**) {210  test();211  static_assert(test());212  testException();213  return 0;214}215