brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · 820ff9e Raw
295 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 const&);16 17#include <cassert>18#include <type_traits>19#include <variant>20 21#include "test_macros.h"22#include "test_workarounds.h"23 24struct NonT {25  constexpr NonT(int v) : value(v) {}26  constexpr NonT(const NonT& o) : value(o.value) {}27  int value;28};29static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");30 31struct NoCopy {32  NoCopy(const NoCopy&) = delete;33};34 35struct MoveOnly {36  MoveOnly(const MoveOnly&) = delete;37  MoveOnly(MoveOnly&&)      = default;38};39 40struct MoveOnlyNT {41  MoveOnlyNT(const MoveOnlyNT&) = delete;42  MoveOnlyNT(MoveOnlyNT&&) {}43};44 45struct NTCopy {46  constexpr NTCopy(int v) : value(v) {}47  NTCopy(const NTCopy& that) : value(that.value) {}48  NTCopy(NTCopy&&) = delete;49  int value;50};51 52static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "");53static_assert(std::is_copy_constructible<NTCopy>::value, "");54 55struct TCopy {56  constexpr TCopy(int v) : value(v) {}57  TCopy(TCopy const&) = default;58  TCopy(TCopy&&)      = delete;59  int value;60};61 62static_assert(std::is_trivially_copy_constructible<TCopy>::value, "");63 64struct TCopyNTMove {65  constexpr TCopyNTMove(int v) : value(v) {}66  TCopyNTMove(const TCopyNTMove&) = default;67  TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; }68  int value;69};70 71static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");72 73#ifndef TEST_HAS_NO_EXCEPTIONS74struct MakeEmptyT {75  static int alive;76  MakeEmptyT() { ++alive; }77  MakeEmptyT(const MakeEmptyT&) {78    ++alive;79    // Don't throw from the copy constructor since variant's assignment80    // operator performs a copy before committing to the assignment.81  }82  MakeEmptyT(MakeEmptyT&&) { throw 42; }83  MakeEmptyT& operator=(const MakeEmptyT&) { throw 42; }84  MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }85  ~MakeEmptyT() { --alive; }86};87 88int MakeEmptyT::alive = 0;89 90template <class Variant>91void makeEmpty(Variant& v) {92  Variant v2(std::in_place_type<MakeEmptyT>);93  try {94    v = std::move(v2);95    assert(false);96  } catch (...) {97    assert(v.valueless_by_exception());98  }99}100#endif // TEST_HAS_NO_EXCEPTIONS101 102constexpr void test_copy_ctor_sfinae() {103  {104    using V = std::variant<int, long>;105    static_assert(std::is_copy_constructible<V>::value, "");106  }107  {108    using V = std::variant<int, NoCopy>;109    static_assert(!std::is_copy_constructible<V>::value, "");110  }111  {112    using V = std::variant<int, MoveOnly>;113    static_assert(!std::is_copy_constructible<V>::value, "");114  }115  {116    using V = std::variant<int, MoveOnlyNT>;117    static_assert(!std::is_copy_constructible<V>::value, "");118  }119 120  // Make sure we properly propagate triviality (see P0602R4).121  {122    using V = std::variant<int, long>;123    static_assert(std::is_trivially_copy_constructible<V>::value, "");124  }125  {126    using V = std::variant<int, NTCopy>;127    static_assert(!std::is_trivially_copy_constructible<V>::value, "");128    static_assert(std::is_copy_constructible<V>::value, "");129  }130  {131    using V = std::variant<int, TCopy>;132    static_assert(std::is_trivially_copy_constructible<V>::value, "");133  }134  {135    using V = std::variant<int, TCopyNTMove>;136    static_assert(std::is_trivially_copy_constructible<V>::value, "");137  }138}139 140TEST_CONSTEXPR_CXX20 void test_copy_ctor_basic() {141  {142    std::variant<int> v(std::in_place_index<0>, 42);143    std::variant<int> v2 = v;144    assert(v2.index() == 0);145    assert(std::get<0>(v2) == 42);146  }147  {148    std::variant<int, long> v(std::in_place_index<1>, 42);149    std::variant<int, long> v2 = v;150    assert(v2.index() == 1);151    assert(std::get<1>(v2) == 42);152  }153  {154    std::variant<NonT> v(std::in_place_index<0>, 42);155    assert(v.index() == 0);156    std::variant<NonT> v2(v);157    assert(v2.index() == 0);158    assert(std::get<0>(v2).value == 42);159  }160  {161    std::variant<int, NonT> v(std::in_place_index<1>, 42);162    assert(v.index() == 1);163    std::variant<int, NonT> v2(v);164    assert(v2.index() == 1);165    assert(std::get<1>(v2).value == 42);166  }167 168  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).169  {170    constexpr std::variant<int> v(std::in_place_index<0>, 42);171    static_assert(v.index() == 0, "");172    constexpr std::variant<int> v2 = v;173    static_assert(v2.index() == 0, "");174    static_assert(std::get<0>(v2) == 42, "");175  }176  {177    constexpr std::variant<int, long> v(std::in_place_index<1>, 42);178    static_assert(v.index() == 1, "");179    constexpr std::variant<int, long> v2 = v;180    static_assert(v2.index() == 1, "");181    static_assert(std::get<1>(v2) == 42, "");182  }183  {184    constexpr std::variant<TCopy> v(std::in_place_index<0>, 42);185    static_assert(v.index() == 0, "");186    constexpr std::variant<TCopy> v2(v);187    static_assert(v2.index() == 0, "");188    static_assert(std::get<0>(v2).value == 42, "");189  }190  {191    constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42);192    static_assert(v.index() == 1, "");193    constexpr std::variant<int, TCopy> v2(v);194    static_assert(v2.index() == 1, "");195    static_assert(std::get<1>(v2).value == 42, "");196  }197  {198    constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42);199    static_assert(v.index() == 0, "");200    constexpr std::variant<TCopyNTMove> v2(v);201    static_assert(v2.index() == 0, "");202    static_assert(std::get<0>(v2).value == 42, "");203  }204  {205    constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42);206    static_assert(v.index() == 1, "");207    constexpr std::variant<int, TCopyNTMove> v2(v);208    static_assert(v2.index() == 1, "");209    static_assert(std::get<1>(v2).value == 42, "");210  }211}212 213void test_copy_ctor_valueless_by_exception() {214#ifndef TEST_HAS_NO_EXCEPTIONS215  using V = std::variant<int, MakeEmptyT>;216  V v1;217  makeEmpty(v1);218  const V& cv1 = v1;219  V v(cv1);220  assert(v.valueless_by_exception());221#endif // TEST_HAS_NO_EXCEPTIONS222}223 224template <std::size_t Idx, class T>225constexpr void test_constexpr_copy_ctor_imp(const T& v) {226  auto v2 = v;227  assert(v2.index() == v.index());228  assert(v2.index() == Idx);229  assert(std::get<Idx>(v2) == std::get<Idx>(v));230}231 232constexpr void test_constexpr_copy_ctor_trivial() {233  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).234  using V = std::variant<long, void*, const int>;235#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE236  static_assert(std::is_trivially_destructible<V>::value, "");237  static_assert(std::is_trivially_copy_constructible<V>::value, "");238  static_assert(std::is_trivially_move_constructible<V>::value, "");239  static_assert(!std::is_copy_assignable<V>::value, "");240  static_assert(!std::is_move_assignable<V>::value, "");241#else  // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE242  static_assert(std::is_trivially_copyable<V>::value, "");243#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE244  static_assert(std::is_trivially_copy_constructible<V>::value, "");245  test_constexpr_copy_ctor_imp<0>(V(42l));246  test_constexpr_copy_ctor_imp<1>(V(nullptr));247  test_constexpr_copy_ctor_imp<2>(V(101));248}249 250struct NonTrivialCopyCtor {251  int i = 0;252  constexpr NonTrivialCopyCtor(int ii) : i(ii) {}253  constexpr NonTrivialCopyCtor(const NonTrivialCopyCtor& other) : i(other.i) {}254  constexpr NonTrivialCopyCtor(NonTrivialCopyCtor&& other) = default;255  TEST_CONSTEXPR_CXX20 ~NonTrivialCopyCtor()               = default;256  friend constexpr bool operator==(const NonTrivialCopyCtor& x, const NonTrivialCopyCtor& y) { return x.i == y.i; }257};258 259TEST_CONSTEXPR_CXX20 void test_constexpr_copy_ctor_non_trivial() {260  // Test !is_trivially_move_constructible261  using V = std::variant<long, NonTrivialCopyCtor, void*>;262  static_assert(!std::is_trivially_copy_constructible<V>::value, "");263  test_constexpr_copy_ctor_imp<0>(V(42l));264  test_constexpr_copy_ctor_imp<1>(V(NonTrivialCopyCtor(5)));265  test_constexpr_copy_ctor_imp<2>(V(nullptr));266}267 268void non_constexpr_test() { test_copy_ctor_valueless_by_exception(); }269 270constexpr bool cxx17_constexpr_test() {271  test_copy_ctor_sfinae();272  test_constexpr_copy_ctor_trivial();273 274  return true;275}276 277TEST_CONSTEXPR_CXX20 bool cxx20_constexpr_test() {278  test_copy_ctor_basic();279  test_constexpr_copy_ctor_non_trivial();280 281  return true;282}283 284int main(int, char**) {285  non_constexpr_test();286  cxx17_constexpr_test();287  cxx20_constexpr_test();288 289  static_assert(cxx17_constexpr_test());290#if TEST_STD_VER >= 20291  static_assert(cxx20_constexpr_test());292#endif293  return 0;294}295