brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.6 KiB · 4e8453c Raw
369 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// constexpr variant(variant&&) noexcept(see below);16 17#include <cassert>18#include <string>19#include <type_traits>20#include <variant>21 22#include "test_macros.h"23#include "test_workarounds.h"24 25struct ThrowsMove {26  ThrowsMove(ThrowsMove&&) noexcept(false) {}27};28 29struct NoCopy {30  NoCopy(const NoCopy&) = delete;31};32 33struct MoveOnly {34  int value;35  constexpr MoveOnly(int v) : value(v) {}36  MoveOnly(const MoveOnly&) = delete;37  MoveOnly(MoveOnly&&)      = default;38};39 40struct MoveOnlyNT {41  int value;42  constexpr MoveOnlyNT(int v) : value(v) {}43  MoveOnlyNT(const MoveOnlyNT&) = delete;44  constexpr MoveOnlyNT(MoveOnlyNT&& other) : value(other.value) { other.value = -1; }45};46 47struct NTMove {48  constexpr NTMove(int v) : value(v) {}49  NTMove(const NTMove&) = delete;50  NTMove(NTMove&& that) : value(that.value) { that.value = -1; }51  int value;52};53 54static_assert(!std::is_trivially_move_constructible<NTMove>::value, "");55static_assert(std::is_move_constructible<NTMove>::value, "");56 57struct TMove {58  constexpr TMove(int v) : value(v) {}59  TMove(const TMove&) = delete;60  TMove(TMove&&)      = default;61  int value;62};63 64static_assert(std::is_trivially_move_constructible<TMove>::value, "");65 66struct TMoveNTCopy {67  constexpr TMoveNTCopy(int v) : value(v) {}68  TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {}69  TMoveNTCopy(TMoveNTCopy&&) = default;70  int value;71};72 73static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, "");74 75#ifndef TEST_HAS_NO_EXCEPTIONS76struct MakeEmptyT {77  static int alive;78  MakeEmptyT() { ++alive; }79  MakeEmptyT(const MakeEmptyT&) {80    ++alive;81    // Don't throw from the copy constructor since variant's assignment82    // operator performs a copy before committing to the assignment.83  }84  MakeEmptyT(MakeEmptyT&&) { throw 42; }85  MakeEmptyT& operator=(const MakeEmptyT&) { throw 42; }86  MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }87  ~MakeEmptyT() { --alive; }88};89 90int MakeEmptyT::alive = 0;91 92template <class Variant>93void makeEmpty(Variant& v) {94  Variant v2(std::in_place_type<MakeEmptyT>);95  try {96    v = std::move(v2);97    assert(false);98  } catch (...) {99    assert(v.valueless_by_exception());100  }101}102#endif // TEST_HAS_NO_EXCEPTIONS103 104constexpr void test_move_noexcept() {105  {106    using V = std::variant<int, long>;107    static_assert(std::is_nothrow_move_constructible<V>::value, "");108  }109  {110    using V = std::variant<int, MoveOnly>;111    static_assert(std::is_nothrow_move_constructible<V>::value, "");112  }113  {114    using V = std::variant<int, MoveOnlyNT>;115    static_assert(!std::is_nothrow_move_constructible<V>::value, "");116  }117  {118    using V = std::variant<int, ThrowsMove>;119    static_assert(!std::is_nothrow_move_constructible<V>::value, "");120  }121}122 123constexpr void test_move_ctor_sfinae() {124  {125    using V = std::variant<int, long>;126    static_assert(std::is_move_constructible<V>::value, "");127  }128  {129    using V = std::variant<int, MoveOnly>;130    static_assert(std::is_move_constructible<V>::value, "");131  }132  {133    using V = std::variant<int, MoveOnlyNT>;134    static_assert(std::is_move_constructible<V>::value, "");135  }136  {137    using V = std::variant<int, NoCopy>;138    static_assert(!std::is_move_constructible<V>::value, "");139  }140 141  // Make sure we properly propagate triviality (see P0602R4).142  {143    using V = std::variant<int, long>;144    static_assert(std::is_trivially_move_constructible<V>::value, "");145  }146  {147    using V = std::variant<int, NTMove>;148    static_assert(!std::is_trivially_move_constructible<V>::value, "");149    static_assert(std::is_move_constructible<V>::value, "");150  }151  {152    using V = std::variant<int, TMove>;153    static_assert(std::is_trivially_move_constructible<V>::value, "");154  }155  {156    using V = std::variant<int, TMoveNTCopy>;157    static_assert(std::is_trivially_move_constructible<V>::value, "");158  }159}160 161template <typename T>162struct Result {163  std::size_t index;164  T value;165};166 167TEST_CONSTEXPR_CXX20 void test_move_ctor_basic() {168  {169    std::variant<int> v(std::in_place_index<0>, 42);170    std::variant<int> v2 = std::move(v);171    assert(v2.index() == 0);172    assert(std::get<0>(v2) == 42);173  }174  {175    std::variant<int, long> v(std::in_place_index<1>, 42);176    std::variant<int, long> v2 = std::move(v);177    assert(v2.index() == 1);178    assert(std::get<1>(v2) == 42);179  }180  {181    std::variant<MoveOnly> v(std::in_place_index<0>, 42);182    assert(v.index() == 0);183    std::variant<MoveOnly> v2(std::move(v));184    assert(v2.index() == 0);185    assert(std::get<0>(v2).value == 42);186  }187  {188    std::variant<int, MoveOnly> v(std::in_place_index<1>, 42);189    assert(v.index() == 1);190    std::variant<int, MoveOnly> v2(std::move(v));191    assert(v2.index() == 1);192    assert(std::get<1>(v2).value == 42);193  }194  {195    std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42);196    assert(v.index() == 0);197    std::variant<MoveOnlyNT> v2(std::move(v));198    assert(v2.index() == 0);199    assert(std::get<0>(v).value == -1);200    assert(std::get<0>(v2).value == 42);201  }202  {203    std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42);204    assert(v.index() == 1);205    std::variant<int, MoveOnlyNT> v2(std::move(v));206    assert(v2.index() == 1);207    assert(std::get<1>(v).value == -1);208    assert(std::get<1>(v2).value == 42);209  }210 211  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).212  {213    struct {214      constexpr Result<int> operator()() const {215        std::variant<int> v(std::in_place_index<0>, 42);216        std::variant<int> v2 = std::move(v);217        return {v2.index(), std::get<0>(std::move(v2))};218      }219    } test;220    constexpr auto result = test();221    static_assert(result.index == 0, "");222    static_assert(result.value == 42, "");223  }224  {225    struct {226      constexpr Result<long> operator()() const {227        std::variant<int, long> v(std::in_place_index<1>, 42);228        std::variant<int, long> v2 = std::move(v);229        return {v2.index(), std::get<1>(std::move(v2))};230      }231    } test;232    constexpr auto result = test();233    static_assert(result.index == 1, "");234    static_assert(result.value == 42, "");235  }236  {237    struct {238      constexpr Result<TMove> operator()() const {239        std::variant<TMove> v(std::in_place_index<0>, 42);240        std::variant<TMove> v2(std::move(v));241        return {v2.index(), std::get<0>(std::move(v2))};242      }243    } test;244    constexpr auto result = test();245    static_assert(result.index == 0, "");246    static_assert(result.value.value == 42, "");247  }248  {249    struct {250      constexpr Result<TMove> operator()() const {251        std::variant<int, TMove> v(std::in_place_index<1>, 42);252        std::variant<int, TMove> v2(std::move(v));253        return {v2.index(), std::get<1>(std::move(v2))};254      }255    } test;256    constexpr auto result = test();257    static_assert(result.index == 1, "");258    static_assert(result.value.value == 42, "");259  }260  {261    struct {262      constexpr Result<TMoveNTCopy> operator()() const {263        std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42);264        std::variant<TMoveNTCopy> v2(std::move(v));265        return {v2.index(), std::get<0>(std::move(v2))};266      }267    } test;268    constexpr auto result = test();269    static_assert(result.index == 0, "");270    static_assert(result.value.value == 42, "");271  }272  {273    struct {274      constexpr Result<TMoveNTCopy> operator()() const {275        std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42);276        std::variant<int, TMoveNTCopy> v2(std::move(v));277        return {v2.index(), std::get<1>(std::move(v2))};278      }279    } test;280    constexpr auto result = test();281    static_assert(result.index == 1, "");282    static_assert(result.value.value == 42, "");283  }284}285 286void test_move_ctor_valueless_by_exception() {287#ifndef TEST_HAS_NO_EXCEPTIONS288  using V = std::variant<int, MakeEmptyT>;289  V v1;290  makeEmpty(v1);291  V v(std::move(v1));292  assert(v.valueless_by_exception());293#endif // TEST_HAS_NO_EXCEPTIONS294}295 296template <std::size_t Idx, class T>297constexpr void test_constexpr_ctor_imp(const T& v) {298  auto copy = v;299  auto v2   = std::move(copy);300  assert(v2.index() == v.index());301  assert(v2.index() == Idx);302  assert(std::get<Idx>(v2) == std::get<Idx>(v));303}304 305constexpr void test_constexpr_move_ctor_trivial() {306  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).307  using V = std::variant<long, void*, const int>;308#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE309  static_assert(std::is_trivially_destructible<V>::value, "");310  static_assert(std::is_trivially_copy_constructible<V>::value, "");311  static_assert(std::is_trivially_move_constructible<V>::value, "");312  static_assert(!std::is_copy_assignable<V>::value, "");313  static_assert(!std::is_move_assignable<V>::value, "");314#else  // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE315  static_assert(std::is_trivially_copyable<V>::value, "");316#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE317  static_assert(std::is_trivially_move_constructible<V>::value, "");318  test_constexpr_ctor_imp<0>(V(42l));319  test_constexpr_ctor_imp<1>(V(nullptr));320  test_constexpr_ctor_imp<2>(V(101));321}322 323struct NonTrivialMoveCtor {324  int i = 0;325  constexpr NonTrivialMoveCtor(int ii) : i(ii) {}326  constexpr NonTrivialMoveCtor(const NonTrivialMoveCtor& other) = default;327  constexpr NonTrivialMoveCtor(NonTrivialMoveCtor&& other) : i(other.i) {}328  TEST_CONSTEXPR_CXX20 ~NonTrivialMoveCtor() = default;329  friend constexpr bool operator==(const NonTrivialMoveCtor& x, const NonTrivialMoveCtor& y) { return x.i == y.i; }330};331 332TEST_CONSTEXPR_CXX20 void test_constexpr_move_ctor_non_trivial() {333  using V = std::variant<long, NonTrivialMoveCtor, void*>;334  static_assert(!std::is_trivially_move_constructible<V>::value, "");335  test_constexpr_ctor_imp<0>(V(42l));336  test_constexpr_ctor_imp<1>(V(NonTrivialMoveCtor(5)));337  test_constexpr_ctor_imp<2>(V(nullptr));338}339 340void non_constexpr_test() { test_move_ctor_valueless_by_exception(); }341 342constexpr bool cxx17_constexpr_test() {343  test_move_noexcept();344  test_move_ctor_sfinae();345  test_constexpr_move_ctor_trivial();346 347  return true;348}349 350TEST_CONSTEXPR_CXX20 bool cxx20_constexpr_test() {351  test_move_ctor_basic();352  test_constexpr_move_ctor_non_trivial();353 354  return true;355}356 357int main(int, char**) {358  non_constexpr_test();359  cxx17_constexpr_test();360  cxx20_constexpr_test();361 362  static_assert(cxx17_constexpr_test());363#if TEST_STD_VER >= 20364  static_assert(cxx20_constexpr_test());365#endif366 367  return 0;368}369