brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.1 KiB · cc1b171 Raw
339 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++1410// <optional>11 12// From LWG2451:13// template <class U>14// optional<T>& operator=(optional<U>&& rhs);15 16#include <optional>17 18#include <array>19#include <cassert>20#include <memory>21#include <type_traits>22 23#include "test_macros.h"24#include "archetypes.h"25 26using std::optional;27 28struct X29{30    static bool throw_now;31 32    X() = default;33    X(int &&)34    {35        if (throw_now)36            TEST_THROW(6);37    }38};39 40bool X::throw_now = false;41 42struct Y143{44    Y1() = default;45    Y1(const int&) {}46    Y1& operator=(const Y1&) = delete;47};48 49struct Y250{51    Y2() = default;52    Y2(const int&) = delete;53    Y2& operator=(const int&) { return *this; }54};55 56struct B { virtual ~B() = default; };57class D : public B {};58 59 60template <class T>61struct AssignableFrom {62  static int type_constructed;63  static int type_assigned;64static int int_constructed;65  static int int_assigned;66 67  static void reset() {68      type_constructed = int_constructed = 0;69      type_assigned = int_assigned = 0;70  }71 72  AssignableFrom() = default;73 74  explicit AssignableFrom(T) { ++type_constructed; }75  AssignableFrom& operator=(T) { ++type_assigned; return *this; }76 77  AssignableFrom(int) { ++int_constructed; }78  AssignableFrom& operator=(int) { ++int_assigned; return *this; }79private:80  AssignableFrom(AssignableFrom const&) = delete;81  AssignableFrom& operator=(AssignableFrom const&) = delete;82};83 84template <class T> int AssignableFrom<T>::type_constructed = 0;85template <class T> int AssignableFrom<T>::type_assigned = 0;86template <class T> int AssignableFrom<T>::int_constructed = 0;87template <class T> int AssignableFrom<T>::int_assigned = 0;88 89void test_with_test_type() {90    using T = TestTypes::TestType;91    T::reset();92    { // non-empty to empty93        T::reset_constructors();94        optional<T> opt;95        optional<int> other(42);96        opt = std::move(other);97        assert(T::alive == 1);98        assert(T::constructed == 1);99        assert(T::value_constructed == 1);100        assert(T::assigned == 0);101        assert(T::destroyed == 0);102        assert(static_cast<bool>(other) == true);103        assert(*other == 42);104        assert(static_cast<bool>(opt) == true);105        assert(*opt == T(42));106    }107    assert(T::alive == 0);108    { // non-empty to non-empty109        optional<T> opt(101);110        optional<int> other(42);111        T::reset_constructors();112        opt = std::move(other);113        assert(T::alive == 1);114        assert(T::constructed == 0);115        assert(T::assigned == 1);116        assert(T::value_assigned == 1);117        assert(T::destroyed == 0);118        assert(static_cast<bool>(other) == true);119        assert(*other == 42);120        assert(static_cast<bool>(opt) == true);121        assert(*opt == T(42));122    }123    assert(T::alive == 0);124    { // empty to non-empty125        optional<T> opt(101);126        optional<int> other;127        T::reset_constructors();128        opt = std::move(other);129        assert(T::alive == 0);130        assert(T::constructed == 0);131        assert(T::assigned == 0);132        assert(T::destroyed == 1);133        assert(static_cast<bool>(other) == false);134        assert(static_cast<bool>(opt) == false);135    }136    assert(T::alive == 0);137    { // empty to empty138        optional<T> opt;139        optional<int> other;140        T::reset_constructors();141        opt = std::move(other);142        assert(T::alive == 0);143        assert(T::constructed == 0);144        assert(T::assigned == 0);145        assert(T::destroyed == 0);146        assert(static_cast<bool>(other) == false);147        assert(static_cast<bool>(opt) == false);148    }149    assert(T::alive == 0);150}151 152 153void test_ambiguous_assign() {154    using OptInt = std::optional<int>;155    {156        using T = AssignableFrom<OptInt&&>;157        T::reset();158        {159            OptInt a(42);160            std::optional<T> t;161            t = std::move(a);162            assert(T::type_constructed == 1);163            assert(T::type_assigned == 0);164            assert(T::int_constructed == 0);165            assert(T::int_assigned == 0);166        }167        {168            using Opt = std::optional<T>;169            static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, "");170            static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");171            static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");172        }173    }174    {175        using T = AssignableFrom<OptInt const&&>;176        T::reset();177        {178            const OptInt a(42);179            std::optional<T> t;180            t = std::move(a);181            assert(T::type_constructed == 1);182            assert(T::type_assigned == 0);183            assert(T::int_constructed == 0);184            assert(T::int_assigned == 0);185        }186        T::reset();187        {188            OptInt a(42);189            std::optional<T> t;190            t = std::move(a);191            assert(T::type_constructed == 1);192            assert(T::type_assigned == 0);193            assert(T::int_constructed == 0);194            assert(T::int_assigned == 0);195        }196        {197            using Opt = std::optional<T>;198            static_assert(std::is_assignable<Opt&, OptInt&&>::value, "");199            static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");200            static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");201        }202    }203}204 205 206TEST_CONSTEXPR_CXX20 bool test()207{208    {209        optional<int> opt;210        optional<short> opt2;211        opt = std::move(opt2);212        assert(static_cast<bool>(opt2) == false);213        assert(static_cast<bool>(opt) == static_cast<bool>(opt2));214    }215    {216        optional<int> opt;217        optional<short> opt2(short{2});218        opt = std::move(opt2);219        assert(static_cast<bool>(opt2) == true);220        assert(*opt2 == 2);221        assert(static_cast<bool>(opt) == static_cast<bool>(opt2));222        assert(*opt == *opt2);223    }224    {225        optional<int> opt(3);226        optional<short> opt2;227        opt = std::move(opt2);228        assert(static_cast<bool>(opt2) == false);229        assert(static_cast<bool>(opt) == static_cast<bool>(opt2));230    }231    {232        optional<int> opt(3);233        optional<short> opt2(short{2});234        opt = std::move(opt2);235        assert(static_cast<bool>(opt2) == true);236        assert(*opt2 == 2);237        assert(static_cast<bool>(opt) == static_cast<bool>(opt2));238        assert(*opt == *opt2);239    }240 241    enum class state_t { inactive, constructed, copy_assigned, move_assigned };242    class StateTracker {243    public:244      constexpr StateTracker(state_t& s)245      : state_(&s)246      {247        *state_ = state_t::constructed;248      }249 250      StateTracker(StateTracker&&) = default;251      StateTracker(StateTracker const&) = default;252 253      constexpr StateTracker& operator=(StateTracker&& other) noexcept254      {255        *state_ = state_t::inactive;256        state_ = other.state_;257        *state_ = state_t::move_assigned;258        other.state_ = nullptr;259        return *this;260      }261 262      constexpr StateTracker& operator=(StateTracker const& other) noexcept263      {264        *state_ = state_t::inactive;265        state_ = other.state_;266        *state_ = state_t::copy_assigned;267        return *this;268      }269    private:270      state_t* state_;271    };272    {273      auto state = std::array{state_t::inactive, state_t::inactive};274      auto opt1 = std::optional<StateTracker>(state[0]);275      assert(state[0] == state_t::constructed);276 277      auto opt2 = std::optional<StateTracker>(state[1]);278      assert(state[1] == state_t::constructed);279 280      opt1 = std::move(opt2);281      assert(state[0] == state_t::inactive);282      assert(state[1] == state_t::move_assigned);283    }284    {285      auto state = std::array{state_t::inactive, state_t::inactive};286      auto opt1 = std::optional<StateTracker>(state[0]);287      assert(state[0] == state_t::constructed);288 289      auto opt2 = std::optional<StateTracker>(state[1]);290      assert(state[1] == state_t::constructed);291 292      opt1 = opt2;293      assert(state[0] == state_t::inactive);294      assert(state[1] == state_t::copy_assigned);295    }296 297    return true;298}299 300 301int main(int, char**)302{303#if TEST_STD_VER > 17304    static_assert(test());305#endif306    test_with_test_type();307    test_ambiguous_assign();308    test();309    {310        optional<std::unique_ptr<B>> opt;311        optional<std::unique_ptr<D>> other(new D());312        opt = std::move(other);313        assert(static_cast<bool>(opt) == true);314        assert(static_cast<bool>(other) == true);315        assert(opt->get() != nullptr);316        assert(other->get() == nullptr);317    }318#ifndef TEST_HAS_NO_EXCEPTIONS319    {320        optional<X> opt;321        optional<int> opt2(42);322        assert(static_cast<bool>(opt2) == true);323        try324        {325            X::throw_now = true;326            opt = std::move(opt2);327            assert(false);328        }329        catch (int i)330        {331            assert(i == 6);332            assert(static_cast<bool>(opt) == false);333        }334    }335#endif336 337  return 0;338}339