brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.4 KiB · 98faf84 Raw
427 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 11// <variant>12 13// template <class ...Types> class variant;14 15// template <class T>16// variant& operator=(T&&) noexcept(see below);17 18#include <cassert>19#include <string>20#include <type_traits>21#include <variant>22#include <vector>23#include <memory>24 25#include "test_macros.h"26#include "variant_test_helpers.h"27 28namespace MetaHelpers {29 30struct Dummy {31  Dummy() = default;32};33 34struct ThrowsCtorT {35  ThrowsCtorT(int) noexcept(false) {}36  ThrowsCtorT& operator=(int) noexcept { return *this; }37};38 39struct ThrowsAssignT {40  ThrowsAssignT(int) noexcept {}41  ThrowsAssignT& operator=(int) noexcept(false) { return *this; }42};43 44struct NoThrowT {45  NoThrowT(int) noexcept {}46  NoThrowT& operator=(int) noexcept { return *this; }47};48 49} // namespace MetaHelpers50 51namespace RuntimeHelpers {52#ifndef TEST_HAS_NO_EXCEPTIONS53 54struct ThrowsCtorT {55  int value;56  ThrowsCtorT() : value(0) {}57  ThrowsCtorT(int) noexcept(false) { throw 42; }58  ThrowsCtorT& operator=(int v) noexcept {59    value = v;60    return *this;61  }62};63 64struct MoveCrashes {65  int value;66  MoveCrashes(int v = 0) noexcept : value{v} {}67  MoveCrashes(MoveCrashes&&) noexcept { assert(false); }68  MoveCrashes& operator=(MoveCrashes&&) noexcept {69    assert(false);70    return *this;71  }72  MoveCrashes& operator=(int v) noexcept {73    value = v;74    return *this;75  }76};77 78struct ThrowsCtorTandMove {79  int value;80  ThrowsCtorTandMove() : value(0) {}81  ThrowsCtorTandMove(int) noexcept(false) { throw 42; }82  ThrowsCtorTandMove(ThrowsCtorTandMove&&) noexcept(false) { assert(false); }83  ThrowsCtorTandMove& operator=(int v) noexcept {84    value = v;85    return *this;86  }87};88 89struct ThrowsAssignT {90  int value;91  ThrowsAssignT() : value(0) {}92  ThrowsAssignT(int v) noexcept : value(v) {}93  ThrowsAssignT& operator=(int) noexcept(false) { throw 42; }94};95 96struct NoThrowT {97  int value;98  NoThrowT() : value(0) {}99  NoThrowT(int v) noexcept : value(v) {}100  NoThrowT& operator=(int v) noexcept {101    value = v;102    return *this;103  }104};105 106#endif // !defined(TEST_HAS_NO_EXCEPTIONS)107} // namespace RuntimeHelpers108 109constexpr void test_T_assignment_noexcept() {110  using namespace MetaHelpers;111  {112    using V = std::variant<Dummy, NoThrowT>;113    static_assert(std::is_nothrow_assignable<V, int>::value, "");114  }115  {116    using V = std::variant<Dummy, ThrowsCtorT>;117    static_assert(!std::is_nothrow_assignable<V, int>::value, "");118  }119  {120    using V = std::variant<Dummy, ThrowsAssignT>;121    static_assert(!std::is_nothrow_assignable<V, int>::value, "");122  }123}124 125constexpr void test_T_assignment_sfinae() {126  {127    using V = std::variant<long, long long>;128    static_assert(!std::is_assignable<V, int>::value, "ambiguous");129  }130  {131    using V = std::variant<std::string, std::string>;132    static_assert(!std::is_assignable<V, const char*>::value, "ambiguous");133  }134  {135    using V = std::variant<std::string, void*>;136    static_assert(!std::is_assignable<V, int>::value, "no matching operator=");137  }138  {139    using V = std::variant<std::string, float>;140    static_assert(!std::is_assignable<V, int>::value, "no matching operator=");141  }142  {143    using V = std::variant<std::unique_ptr<int>, bool>;144    static_assert(!std::is_assignable<V, std::unique_ptr<char>>::value, "no explicit bool in operator=");145    struct X {146      operator void*();147    };148    static_assert(!std::is_assignable<V, X>::value, "no boolean conversion in operator=");149    static_assert(std::is_assignable<V, std::false_type>::value, "converted to bool in operator=");150  }151  {152    struct X {};153    struct Y {154      operator X();155    };156    using V = std::variant<X>;157    static_assert(std::is_assignable<V, Y>::value, "regression on user-defined conversions in operator=");158  }159}160 161TEST_CONSTEXPR_CXX20 void test_T_assignment_basic() {162  {163    std::variant<int> v(43);164    v = 42;165    assert(v.index() == 0);166    assert(std::get<0>(v) == 42);167  }168  {169    std::variant<int, long> v(43l);170    v = 42;171    assert(v.index() == 0);172    assert(std::get<0>(v) == 42);173    v = 43l;174    assert(v.index() == 1);175    assert(std::get<1>(v) == 43);176  }177  {178    std::variant<unsigned, long> v;179    v = 42;180    assert(v.index() == 1);181    assert(std::get<1>(v) == 42);182    v = 43u;183    assert(v.index() == 0);184    assert(std::get<0>(v) == 43);185  }186  {187    std::variant<std::string, bool> v = true;188    v                                 = "bar";189    assert(v.index() == 0);190    assert(std::get<0>(v) == "bar");191  }192}193 194void test_T_assignment_basic_no_constexpr() {195  std::variant<bool, std::unique_ptr<int>> v;196  v = nullptr;197  assert(v.index() == 1);198  assert(std::get<1>(v) == nullptr);199}200 201struct TraceStat {202  int construct      = 0;203  int copy_construct = 0;204  int copy_assign    = 0;205  int move_construct = 0;206  int move_assign    = 0;207  int T_copy_assign  = 0;208  int T_move_assign  = 0;209  int destroy        = 0;210};211 212template <bool CtorNoexcept, bool MoveCtorNoexcept>213struct Trace {214  struct T {};215 216  constexpr Trace(TraceStat* s) noexcept(CtorNoexcept) : stat(s) { ++s->construct; }217  constexpr Trace(T) noexcept(CtorNoexcept) : stat(nullptr) {}218  constexpr Trace(const Trace& o) : stat(o.stat) { ++stat->copy_construct; }219  constexpr Trace(Trace&& o) noexcept(MoveCtorNoexcept) : stat(o.stat) { ++stat->move_construct; }220  constexpr Trace& operator=(const Trace&) {221    ++stat->copy_assign;222    return *this;223  }224  constexpr Trace& operator=(Trace&&) noexcept {225    ++stat->move_assign;226    return *this;227  }228 229  constexpr Trace& operator=(const T&) {230    ++stat->T_copy_assign;231    return *this;232  }233  constexpr Trace& operator=(T&&) noexcept {234    ++stat->T_move_assign;235    return *this;236  }237  TEST_CONSTEXPR_CXX20 ~Trace() { ++stat->destroy; }238 239  TraceStat* stat;240};241 242TEST_CONSTEXPR_CXX20 void test_T_assignment_performs_construction() {243  {244    using V = std::variant<int, Trace<false, false>>;245    TraceStat stat;246    V v{1};247    v = &stat;248    assert(stat.construct == 1);249    assert(stat.copy_construct == 0);250    assert(stat.move_construct == 0);251    assert(stat.copy_assign == 0);252    assert(stat.move_assign == 0);253    assert(stat.destroy == 0);254  }255  {256    using V = std::variant<int, Trace<false, true>>;257    TraceStat stat;258    V v{1};259    v = &stat;260    assert(stat.construct == 1);261    assert(stat.copy_construct == 0);262    assert(stat.move_construct == 1);263    assert(stat.copy_assign == 0);264    assert(stat.move_assign == 0);265    assert(stat.destroy == 1);266  }267 268  {269    using V = std::variant<int, Trace<true, false>>;270    TraceStat stat;271    V v{1};272    v = &stat;273    assert(stat.construct == 1);274    assert(stat.copy_construct == 0);275    assert(stat.move_construct == 0);276    assert(stat.copy_assign == 0);277    assert(stat.move_assign == 0);278    assert(stat.destroy == 0);279  }280 281  {282    using V = std::variant<int, Trace<true, true>>;283    TraceStat stat;284    V v{1};285    v = &stat;286    assert(stat.construct == 1);287    assert(stat.copy_construct == 0);288    assert(stat.move_construct == 0);289    assert(stat.copy_assign == 0);290    assert(stat.move_assign == 0);291    assert(stat.destroy == 0);292  }293}294 295TEST_CONSTEXPR_CXX20 void test_T_assignment_performs_assignment() {296  {297    using V = std::variant<int, Trace<false, false>>;298    TraceStat stat;299    V v{&stat};300    v = Trace<false, false>::T{};301    assert(stat.construct == 1);302    assert(stat.copy_construct == 0);303    assert(stat.move_construct == 0);304    assert(stat.copy_assign == 0);305    assert(stat.move_assign == 0);306    assert(stat.T_copy_assign == 0);307    assert(stat.T_move_assign == 1);308    assert(stat.destroy == 0);309  }310  {311    using V = std::variant<int, Trace<false, false>>;312    TraceStat stat;313    V v{&stat};314    Trace<false, false>::T t;315    v = t;316    assert(stat.construct == 1);317    assert(stat.copy_construct == 0);318    assert(stat.move_construct == 0);319    assert(stat.copy_assign == 0);320    assert(stat.move_assign == 0);321    assert(stat.T_copy_assign == 1);322    assert(stat.T_move_assign == 0);323    assert(stat.destroy == 0);324  }325}326 327void test_T_assignment_performs_construction_throw() {328  using namespace RuntimeHelpers;329#ifndef TEST_HAS_NO_EXCEPTIONS330  {331    using V = std::variant<std::string, ThrowsCtorT>;332    V v(std::in_place_type<std::string>, "hello");333    try {334      v = 42;335      assert(false);336    } catch (...) { /* ... */337    }338    assert(v.index() == 0);339    assert(std::get<0>(v) == "hello");340  }341  {342    using V = std::variant<ThrowsAssignT, std::string>;343    V v(std::in_place_type<std::string>, "hello");344    v = 42;345    assert(v.index() == 0);346    assert(std::get<0>(v).value == 42);347  }348#endif // TEST_HAS_NO_EXCEPTIONS349}350 351void test_T_assignment_performs_assignment_throw() {352  using namespace RuntimeHelpers;353#ifndef TEST_HAS_NO_EXCEPTIONS354  {355    using V = std::variant<ThrowsCtorT>;356    V v;357    v = 42;358    assert(v.index() == 0);359    assert(std::get<0>(v).value == 42);360  }361  {362    using V = std::variant<ThrowsCtorT, std::string>;363    V v;364    v = 42;365    assert(v.index() == 0);366    assert(std::get<0>(v).value == 42);367  }368  {369    using V = std::variant<ThrowsAssignT>;370    V v(100);371    try {372      v = 42;373      assert(false);374    } catch (...) { /* ... */375    }376    assert(v.index() == 0);377    assert(std::get<0>(v).value == 100);378  }379  {380    using V = std::variant<std::string, ThrowsAssignT>;381    V v(100);382    try {383      v = 42;384      assert(false);385    } catch (...) { /* ... */386    }387    assert(v.index() == 1);388    assert(std::get<1>(v).value == 100);389  }390#endif // TEST_HAS_NO_EXCEPTIONS391}392 393TEST_CONSTEXPR_CXX20 void test_T_assignment_vector_bool() {394  std::vector<bool> vec = {true};395  std::variant<bool, int> v;396  v = vec[0];397  assert(v.index() == 0);398  assert(std::get<0>(v) == true);399}400 401void non_constexpr_test() {402  test_T_assignment_basic_no_constexpr();403  test_T_assignment_performs_construction_throw();404  test_T_assignment_performs_assignment_throw();405}406 407TEST_CONSTEXPR_CXX20 bool test() {408  test_T_assignment_basic();409  test_T_assignment_performs_construction();410  test_T_assignment_performs_assignment();411  test_T_assignment_noexcept();412  test_T_assignment_sfinae();413  test_T_assignment_vector_bool();414 415  return true;416}417 418int main(int, char**) {419  test();420  non_constexpr_test();421 422#if TEST_STD_VER >= 20423  static_assert(test());424#endif425  return 0;426}427