brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.1 KiB · d96a70c Raw
173 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// constexpr expected& operator=(expected&& rhs) noexcept(see below);12//13// Effects:14// - If this->has_value() && rhs.has_value() is true, no effects.15// - Otherwise, if this->has_value() is true, equivalent to:16//   construct_at(addressof(unex), std::move(rhs.unex));17//   has_val = false;18// - Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true.19// - Otherwise, equivalent to unex = std::move(rhs.error()).20//21// Returns: *this.22//23// Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v<E> && is_nothrow_move_assignable_v<E>.24//25// This operator is defined as deleted unless is_move_constructible_v<E> is true and is_move_assignable_v<E> is true.26 27#include <cassert>28#include <concepts>29#include <expected>30#include <type_traits>31#include <utility>32 33#include "../../types.h"34#include "test_macros.h"35 36struct NotMoveConstructible {37  NotMoveConstructible(NotMoveConstructible&&)            = delete;38  NotMoveConstructible& operator=(NotMoveConstructible&&) = default;39};40 41struct NotMoveAssignable {42  NotMoveAssignable(NotMoveAssignable&&)            = default;43  NotMoveAssignable& operator=(NotMoveAssignable&&) = delete;44};45 46// Test constraints47static_assert(std::is_move_assignable_v<std::expected<void, int>>);48 49// !is_move_assignable_v<E>50static_assert(!std::is_move_assignable_v<std::expected<void, NotMoveAssignable>>);51 52// !is_move_constructible_v<E>53static_assert(!std::is_move_assignable_v<std::expected<void, NotMoveConstructible>>);54 55// Test noexcept56struct MoveCtorMayThrow {57  MoveCtorMayThrow(MoveCtorMayThrow&&) noexcept(false) {}58  MoveCtorMayThrow& operator=(MoveCtorMayThrow&&) noexcept = default;59};60 61struct MoveAssignMayThrow {62  MoveAssignMayThrow(MoveAssignMayThrow&&) noexcept = default;63  MoveAssignMayThrow& operator=(MoveAssignMayThrow&&) noexcept(false) { return *this; }64};65 66// Test noexcept67static_assert(std::is_nothrow_move_assignable_v<std::expected<void, int>>);68 69// !is_nothrow_move_assignable_v<E>70static_assert(!std::is_nothrow_move_assignable_v<std::expected<void, MoveAssignMayThrow>>);71 72// !is_nothrow_move_constructible_v<E>73static_assert(!std::is_nothrow_move_assignable_v<std::expected<void, MoveCtorMayThrow>>);74 75constexpr bool test() {76  // If this->has_value() && rhs.has_value() is true, no effects.77  {78    std::expected<void, int> e1;79    std::expected<void, int> e2;80    decltype(auto) x = (e1 = std::move(e2));81    static_assert(std::same_as<decltype(x), std::expected<void, int>&>);82    assert(&x == &e1);83    assert(e1.has_value());84  }85 86  // Otherwise, if this->has_value() is true, equivalent to:87  // construct_at(addressof(unex), std::move(rhs.unex));88  // has_val = false;89  {90    Traced::state state{};91    std::expected<void, Traced> e1;92    std::expected<void, Traced> e2(std::unexpect, state, 5);93    decltype(auto) x = (e1 = std::move(e2));94    static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);95    assert(&x == &e1);96    assert(!e1.has_value());97    assert(e1.error().data_ == 5);98 99    assert(state.moveCtorCalled);100  }101 102  // Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true.103  {104    Traced::state state{};105    std::expected<void, Traced> e1(std::unexpect, state, 5);106    std::expected<void, Traced> e2;107    decltype(auto) x = (e1 = std::move(e2));108    static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);109    assert(&x == &e1);110    assert(e1.has_value());111 112    assert(state.dtorCalled);113  }114 115  // Otherwise, equivalent to unex = rhs.error().116  {117    Traced::state state{};118    std::expected<void, Traced> e1(std::unexpect, state, 5);119    std::expected<void, Traced> e2(std::unexpect, state, 10);120    decltype(auto) x = (e1 = std::move(e2));121    static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);122    assert(&x == &e1);123    assert(!e1.has_value());124    assert(e1.error().data_ == 10);125 126    assert(state.moveAssignCalled);127  }128 129  // CheckForInvalidWrites130  {131    {132      CheckForInvalidWrites<true, true> e1;133      CheckForInvalidWrites<true, true> e2(std::unexpect);134 135      e1 = std::move(e2);136 137      assert(e1.check());138      assert(e2.check());139    }140    {141      CheckForInvalidWrites<false, true> e1;142      CheckForInvalidWrites<false, true> e2(std::unexpect);143 144      e1 = std::move(e2);145 146      assert(e1.check());147      assert(e2.check());148    }149  }150 151  return true;152}153 154void testException() {155#ifndef TEST_HAS_NO_EXCEPTIONS156  std::expected<void, ThrowOnMoveConstruct> e1(std::in_place);157  std::expected<void, ThrowOnMoveConstruct> e2(std::unexpect);158  try {159    e1 = std::move(e2);160    assert(false);161  } catch (Except) {162    assert(e1.has_value());163  }164#endif // TEST_HAS_NO_EXCEPTIONS165}166 167int main(int, char**) {168  test();169  static_assert(test());170  testException();171  return 0;172}173