Home | History | Annotate | Download | only in optional.object.assign
      1 //===----------------------------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 // UNSUPPORTED: c++98, c++03, c++11, c++14
     11 // <optional>
     12 
     13 // From LWG2451:
     14 // template <class U>
     15 // optional<T>& operator=(optional<U>&& rhs);
     16 
     17 #include <optional>
     18 #include <type_traits>
     19 #include <memory>
     20 #include <cassert>
     21 
     22 #include "test_macros.h"
     23 #include "archetypes.hpp"
     24 
     25 using std::optional;
     26 
     27 struct X
     28 {
     29     static bool throw_now;
     30 
     31     X() = default;
     32     X(int &&)
     33     {
     34         if (throw_now)
     35             TEST_THROW(6);
     36     }
     37 };
     38 
     39 bool X::throw_now = false;
     40 
     41 struct Y1
     42 {
     43     Y1() = default;
     44     Y1(const int&) {}
     45     Y1& operator=(const Y1&) = delete;
     46 };
     47 
     48 struct Y2
     49 {
     50     Y2() = default;
     51     Y2(const int&) = delete;
     52     Y2& operator=(const int&) { return *this; }
     53 };
     54 
     55 class B {};
     56 class D : public B {};
     57 
     58 
     59 template <class T>
     60 struct AssignableFrom {
     61   static int type_constructed;
     62   static int type_assigned;
     63 static int int_constructed;
     64   static int int_assigned;
     65 
     66   static void reset() {
     67       type_constructed = int_constructed = 0;
     68       type_assigned = int_assigned = 0;
     69   }
     70 
     71   AssignableFrom() = default;
     72 
     73   explicit AssignableFrom(T) { ++type_constructed; }
     74   AssignableFrom& operator=(T) { ++type_assigned; return *this; }
     75 
     76   AssignableFrom(int) { ++int_constructed; }
     77   AssignableFrom& operator=(int) { ++int_assigned; return *this; }
     78 private:
     79   AssignableFrom(AssignableFrom const&) = delete;
     80   AssignableFrom& operator=(AssignableFrom const&) = delete;
     81 };
     82 
     83 template <class T> int AssignableFrom<T>::type_constructed = 0;
     84 template <class T> int AssignableFrom<T>::type_assigned = 0;
     85 template <class T> int AssignableFrom<T>::int_constructed = 0;
     86 template <class T> int AssignableFrom<T>::int_assigned = 0;
     87 
     88 void test_with_test_type() {
     89     using T = TestTypes::TestType;
     90     T::reset();
     91     { // non-empty to empty
     92         T::reset_constructors();
     93         optional<T> opt;
     94         optional<int> other(42);
     95         opt = std::move(other);
     96         assert(T::alive == 1);
     97         assert(T::constructed == 1);
     98         assert(T::value_constructed == 1);
     99         assert(T::assigned == 0);
    100         assert(T::destroyed == 0);
    101         assert(static_cast<bool>(other) == true);
    102         assert(*other == 42);
    103         assert(static_cast<bool>(opt) == true);
    104         assert(*opt == T(42));
    105     }
    106     assert(T::alive == 0);
    107     { // non-empty to non-empty
    108         optional<T> opt(101);
    109         optional<int> other(42);
    110         T::reset_constructors();
    111         opt = std::move(other);
    112         assert(T::alive == 1);
    113         assert(T::constructed == 0);
    114         assert(T::assigned == 1);
    115         assert(T::value_assigned == 1);
    116         assert(T::destroyed == 0);
    117         assert(static_cast<bool>(other) == true);
    118         assert(*other == 42);
    119         assert(static_cast<bool>(opt) == true);
    120         assert(*opt == T(42));
    121     }
    122     assert(T::alive == 0);
    123     { // empty to non-empty
    124         optional<T> opt(101);
    125         optional<int> other;
    126         T::reset_constructors();
    127         opt = std::move(other);
    128         assert(T::alive == 0);
    129         assert(T::constructed == 0);
    130         assert(T::assigned == 0);
    131         assert(T::destroyed == 1);
    132         assert(static_cast<bool>(other) == false);
    133         assert(static_cast<bool>(opt) == false);
    134     }
    135     assert(T::alive == 0);
    136     { // empty to empty
    137         optional<T> opt;
    138         optional<int> other;
    139         T::reset_constructors();
    140         opt = std::move(other);
    141         assert(T::alive == 0);
    142         assert(T::constructed == 0);
    143         assert(T::assigned == 0);
    144         assert(T::destroyed == 0);
    145         assert(static_cast<bool>(other) == false);
    146         assert(static_cast<bool>(opt) == false);
    147     }
    148     assert(T::alive == 0);
    149 }
    150 
    151 
    152 void test_ambigious_assign() {
    153     using OptInt = std::optional<int>;
    154     {
    155         using T = AssignableFrom<OptInt&&>;
    156         T::reset();
    157         {
    158             OptInt a(42);
    159             std::optional<T> t;
    160             t = std::move(a);
    161             assert(T::type_constructed == 1);
    162             assert(T::type_assigned == 0);
    163             assert(T::int_constructed == 0);
    164             assert(T::int_assigned == 0);
    165         }
    166         {
    167             using Opt = std::optional<T>;
    168             static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, "");
    169             static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
    170             static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
    171         }
    172     }
    173     {
    174         using T = AssignableFrom<OptInt const&&>;
    175         T::reset();
    176         {
    177             const OptInt a(42);
    178             std::optional<T> t;
    179             t = std::move(a);
    180             assert(T::type_constructed == 1);
    181             assert(T::type_assigned == 0);
    182             assert(T::int_constructed == 0);
    183             assert(T::int_assigned == 0);
    184         }
    185         T::reset();
    186         {
    187             OptInt a(42);
    188             std::optional<T> t;
    189             t = std::move(a);
    190             assert(T::type_constructed == 1);
    191             assert(T::type_assigned == 0);
    192             assert(T::int_constructed == 0);
    193             assert(T::int_assigned == 0);
    194         }
    195         {
    196             using Opt = std::optional<T>;
    197             static_assert(std::is_assignable<Opt&, OptInt&&>::value, "");
    198             static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
    199             static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
    200         }
    201     }
    202 }
    203 
    204 
    205 int main()
    206 {
    207     test_with_test_type();
    208     test_ambigious_assign();
    209     {
    210         optional<int> opt;
    211         optional<short> opt2;
    212         opt = std::move(opt2);
    213         assert(static_cast<bool>(opt2) == false);
    214         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
    215     }
    216     {
    217         optional<int> opt;
    218         optional<short> opt2(short{2});
    219         opt = std::move(opt2);
    220         assert(static_cast<bool>(opt2) == true);
    221         assert(*opt2 == 2);
    222         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
    223         assert(*opt == *opt2);
    224     }
    225     {
    226         optional<int> opt(3);
    227         optional<short> opt2;
    228         opt = std::move(opt2);
    229         assert(static_cast<bool>(opt2) == false);
    230         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
    231     }
    232     {
    233         optional<int> opt(3);
    234         optional<short> opt2(short{2});
    235         opt = std::move(opt2);
    236         assert(static_cast<bool>(opt2) == true);
    237         assert(*opt2 == 2);
    238         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
    239         assert(*opt == *opt2);
    240     }
    241     {
    242         optional<std::unique_ptr<B>> opt;
    243         optional<std::unique_ptr<D>> other(new D());
    244         opt = std::move(other);
    245         assert(static_cast<bool>(opt) == true);
    246         assert(static_cast<bool>(other) == true);
    247         assert(opt->get() != nullptr);
    248         assert(other->get() == nullptr);
    249     }
    250 #ifndef TEST_HAS_NO_EXCEPTIONS
    251     {
    252         optional<X> opt;
    253         optional<int> opt2(42);
    254         assert(static_cast<bool>(opt2) == true);
    255         try
    256         {
    257             X::throw_now = true;
    258             opt = std::move(opt2);
    259             assert(false);
    260         }
    261         catch (int i)
    262         {
    263             assert(i == 6);
    264             assert(static_cast<bool>(opt) == false);
    265         }
    266     }
    267 #endif
    268 }
    269