brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.3 KiB · 607113a Raw
285 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// friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y)));12 13#include <cassert>14#include <expected>15#include <type_traits>16#include <utility>17 18#include "../../types.h"19#include "test_macros.h"20 21// Test Constraints:22struct NotSwappable {23  NotSwappable operator=(const NotSwappable&) = delete;24};25void swap(NotSwappable&, NotSwappable&) = delete;26 27static_assert(std::is_swappable_v<std::expected<int, int>>);28 29// !is_swappable_v<T>30static_assert(!std::is_swappable_v<std::expected<NotSwappable, int>>);31 32// !is_swappable_v<E>33static_assert(!std::is_swappable_v<std::expected<int, NotSwappable>>);34 35struct NotMoveConstructible {36  NotMoveConstructible(NotMoveConstructible&&) = delete;37  friend void swap(NotMoveConstructible&, NotMoveConstructible&) {}38};39 40// !is_move_constructible_v<T>41static_assert(!std::is_swappable_v<std::expected<NotMoveConstructible, int>>);42 43// !is_move_constructible_v<E>44static_assert(!std::is_swappable_v<std::expected<int, NotMoveConstructible>>);45 46struct MoveMayThrow {47  MoveMayThrow(MoveMayThrow&&) noexcept(false);48  friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {}49};50 51// !is_nothrow_move_constructible_v<T> && is_nothrow_move_constructible_v<E>52static_assert(std::is_swappable_v<std::expected<MoveMayThrow, int>>);53 54// is_nothrow_move_constructible_v<T> && !is_nothrow_move_constructible_v<E>55static_assert(std::is_swappable_v<std::expected<int, MoveMayThrow>>);56 57// !is_nothrow_move_constructible_v<T> && !is_nothrow_move_constructible_v<E>58static_assert(!std::is_swappable_v<std::expected<MoveMayThrow, MoveMayThrow>>);59 60// Test noexcept61static_assert(std::is_nothrow_swappable_v<std::expected<int, int>>);62 63// !is_nothrow_move_constructible_v<T>64static_assert(!std::is_nothrow_swappable_v<std::expected<MoveMayThrow, int>>);65 66// !is_nothrow_move_constructible_v<E>67static_assert(!std::is_nothrow_swappable_v<std::expected<int, MoveMayThrow>>);68 69struct SwapMayThrow {70  friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {}71};72 73// !is_nothrow_swappable_v<T>74static_assert(!std::is_nothrow_swappable_v<std::expected<SwapMayThrow, int>>);75 76// !is_nothrow_swappable_v<E>77static_assert(!std::is_nothrow_swappable_v<std::expected<int, SwapMayThrow>>);78 79constexpr bool test() {80  // this->has_value() && rhs.has_value()81  {82    std::expected<ADLSwap, int> x(std::in_place, 5);83    std::expected<ADLSwap, int> y(std::in_place, 10);84    swap(x, y);85 86    assert(x.has_value());87    assert(x->i == 10);88    assert(x->adlSwapCalled);89    assert(y.has_value());90    assert(y->i == 5);91    assert(y->adlSwapCalled);92  }93 94  // !this->has_value() && !rhs.has_value()95  {96    std::expected<int, ADLSwap> x(std::unexpect, 5);97    std::expected<int, ADLSwap> y(std::unexpect, 10);98    swap(x, y);99 100    assert(!x.has_value());101    assert(x.error().i == 10);102    assert(x.error().adlSwapCalled);103    assert(!y.has_value());104    assert(y.error().i == 5);105    assert(y.error().adlSwapCalled);106  }107 108  // this->has_value() && !rhs.has_value()109  // && is_nothrow_move_constructible_v<E>110  {111    std::expected<TrackedMove<true>, TrackedMove<true>> e1(std::in_place, 5);112    std::expected<TrackedMove<true>, TrackedMove<true>> e2(std::unexpect, 10);113 114    swap(e1, e2);115 116    assert(!e1.has_value());117    assert(e1.error().i == 10);118    assert(e2.has_value());119    assert(e2->i == 5);120 121    assert(e1.error().numberOfMoves == 2);122    assert(!e1.error().swapCalled);123    assert(e2->numberOfMoves == 1);124    assert(!e2->swapCalled);125  }126 127  // this->has_value() && !rhs.has_value()128  // && !is_nothrow_move_constructible_v<E>129  {130    std::expected<TrackedMove<true>, TrackedMove<false>> e1(std::in_place, 5);131    std::expected<TrackedMove<true>, TrackedMove<false>> e2(std::unexpect, 10);132 133    swap(e1, e2);134 135    assert(!e1.has_value());136    assert(e1.error().i == 10);137    assert(e2.has_value());138    assert(e2->i == 5);139 140    assert(e1.error().numberOfMoves == 1);141    assert(!e1.error().swapCalled);142    assert(e2->numberOfMoves == 2);143    assert(!e2->swapCalled);144  }145 146  // !this->has_value() && rhs.has_value()147  // && is_nothrow_move_constructible_v<E>148  {149    std::expected<TrackedMove<true>, TrackedMove<true>> e1(std::unexpect, 10);150    std::expected<TrackedMove<true>, TrackedMove<true>> e2(std::in_place, 5);151 152    swap(e1, e2);153 154    assert(e1.has_value());155    assert(e1->i == 5);156    assert(!e2.has_value());157    assert(e2.error().i == 10);158 159    assert(e1->numberOfMoves == 1);160    assert(!e1->swapCalled);161    assert(e2.error().numberOfMoves == 2);162    assert(!e2.error().swapCalled);163  }164 165  // !this->has_value() && rhs.has_value()166  // && !is_nothrow_move_constructible_v<E>167  {168    std::expected<TrackedMove<true>, TrackedMove<false>> e1(std::unexpect, 10);169    std::expected<TrackedMove<true>, TrackedMove<false>> e2(std::in_place, 5);170 171    swap(e1, e2);172 173    assert(e1.has_value());174    assert(e1->i == 5);175    assert(!e2.has_value());176    assert(e2.error().i == 10);177 178    assert(e1->numberOfMoves == 2);179    assert(!e1->swapCalled);180    assert(e2.error().numberOfMoves == 1);181    assert(!e2.error().swapCalled);182  }183 184  // TailClobberer185  {186    // is_nothrow_move_constructible_v<E>187    {188      std::expected<TailClobbererNonTrivialMove<0, true>, TailClobbererNonTrivialMove<1, true>> x(std::in_place);189      std::expected<TailClobbererNonTrivialMove<0, true>, TailClobbererNonTrivialMove<1, true>> y(std::unexpect);190 191      swap(x, y);192 193      // Both of these would fail if adjusting the "has value" flags happened194      // _before_ constructing the member objects inside the `swap`.195      assert(!x.has_value());196      assert(y.has_value());197    }198 199    // !is_nothrow_move_constructible_v<E>200    {201      std::expected<TailClobbererNonTrivialMove<0, true>, TailClobbererNonTrivialMove<1, false>> x(std::in_place);202      std::expected<TailClobbererNonTrivialMove<0, true>, TailClobbererNonTrivialMove<1, false>> y(std::unexpect);203 204      swap(x, y);205 206      // Both of these would fail if adjusting the "has value" flags happened207      // _before_ constructing the member objects inside the `swap`.208      assert(!x.has_value());209      assert(y.has_value());210    }211  }212 213  return true;214}215 216void testException() {217#ifndef TEST_HAS_NO_EXCEPTIONS218  // !e1.has_value() && e2.has_value()219  {220    std::expected<ThrowOnMoveConstruct, int> e1(std::unexpect, 5);221    std::expected<ThrowOnMoveConstruct, int> e2(std::in_place);222    try {223      swap(e1, e2);224      assert(false);225    } catch (Except) {226      assert(!e1.has_value());227      assert(e1.error() == 5);228    }229  }230 231  // e1.has_value() && !e2.has_value()232  {233    std::expected<int, ThrowOnMoveConstruct> e1(5);234    std::expected<int, ThrowOnMoveConstruct> e2(std::unexpect);235    try {236      swap(e1, e2);237      assert(false);238    } catch (Except) {239      assert(e1.has_value());240      assert(*e1 == 5);241    }242  }243 244  // TailClobberer245  {246    // is_nothrow_move_constructible_v<E>247    {248      std::expected<TailClobbererNonTrivialMove<0, false, true>, TailClobbererNonTrivialMove<1>> x(std::in_place);249      std::expected<TailClobbererNonTrivialMove<0, false, true>, TailClobbererNonTrivialMove<1>> y(std::unexpect);250      try {251        swap(x, y);252        assert(false);253      } catch (Except) {254        assert(x.has_value());255        // This would fail if `TailClobbererNonTrivialMove<1>` clobbered the256        // flag when rolling back the swap.257        assert(!y.has_value());258      }259    }260 261    // !is_nothrow_move_constructible_v<E>262    {263      std::expected<TailClobbererNonTrivialMove<0>, TailClobbererNonTrivialMove<1, false, true>> x(std::in_place);264      std::expected<TailClobbererNonTrivialMove<0>, TailClobbererNonTrivialMove<1, false, true>> y(std::unexpect);265      try {266        swap(x, y);267        assert(false);268      } catch (Except) {269        // This would fail if `TailClobbererNonTrivialMove<0>` clobbered the270        // flag when rolling back the swap.271        assert(x.has_value());272        assert(!y.has_value());273      }274    }275  }276#endif // TEST_HAS_NO_EXCEPTIONS277}278 279int main(int, char**) {280  test();281  static_assert(test());282  testException();283  return 0;284}285