brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.8 KiB · aeb1297 Raw
225 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++14, c++17, c++20, c++2310 11// <variant>12 13// class variant;14 15// template<class Self, class Visitor>16//   constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++2617 18#include <cassert>19#include <memory>20#include <string>21#include <tuple>22#include <type_traits>23#include <utility>24#include <variant>25 26#include "test_macros.h"27#include "variant_test_helpers.h"28 29void test_call_operator_forwarding() {30  using Fn = ForwardingCallObject;31  Fn obj{};32  const Fn& cobj = obj;33 34  { // test call operator forwarding - single variant, single arg35    using V = std::variant<int>;36    V v(42);37 38    v.visit(obj);39    assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));40    v.visit(cobj);41    assert(Fn::check_call<int&>(CT_Const | CT_LValue));42    v.visit(std::move(obj));43    assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));44    v.visit(std::move(cobj));45    assert(Fn::check_call<int&>(CT_Const | CT_RValue));46  }47  { // test call operator forwarding - single variant, multi arg48    using V = std::variant<int, long, double>;49    V v(42L);50 51    v.visit(obj);52    assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));53    v.visit(cobj);54    assert(Fn::check_call<long&>(CT_Const | CT_LValue));55    v.visit(std::move(obj));56    assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));57    v.visit(std::move(cobj));58    assert(Fn::check_call<long&>(CT_Const | CT_RValue));59  }60}61 62// Applies to non-member `std::visit` only.63void test_argument_forwarding() {64  using Fn = ForwardingCallObject;65  Fn obj{};66  const auto val = CT_LValue | CT_NonConst;67 68  { // single argument - value type69    using V = std::variant<int>;70    V v(42);71    const V& cv = v;72 73    v.visit(obj);74    assert(Fn::check_call<int&>(val));75    cv.visit(obj);76    assert(Fn::check_call<const int&>(val));77    std::move(v).visit(obj);78    assert(Fn::check_call<int&&>(val));79    std::move(cv).visit(obj);80    assert(Fn::check_call<const int&&>(val));81  }82}83 84void test_return_type() {85  using Fn = ForwardingCallObject;86  Fn obj{};87  const Fn& cobj = obj;88 89  { // test call operator forwarding - single variant, single arg90    using V = std::variant<int>;91    V v(42);92 93    static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);94    static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);95    static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);96    static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);97  }98  { // test call operator forwarding - single variant, multi arg99    using V = std::variant<int, long, double>;100    V v(42L);101 102    static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);103    static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);104    static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);105    static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);106  }107}108 109void test_constexpr() {110  constexpr ReturnFirst obj{};111 112  {113    using V = std::variant<int>;114    constexpr V v(42);115 116    static_assert(v.visit(obj) == 42);117  }118  {119    using V = std::variant<short, long, char>;120    constexpr V v(42L);121 122    static_assert(v.visit(obj) == 42);123  }124}125 126void test_exceptions() {127#ifndef TEST_HAS_NO_EXCEPTIONS128  ReturnArity obj{};129 130  auto test = [&](auto&& v) {131    try {132      v.visit(obj);133    } catch (const std::bad_variant_access&) {134      return true;135    } catch (...) {136    }137    return false;138  };139 140  {141    using V = std::variant<int, MakeEmptyT>;142    V v;143    makeEmpty(v);144 145    assert(test(v));146  }147#endif148}149 150// See https://llvm.org/PR31916151void test_caller_accepts_nonconst() {152  struct A {};153  struct Visitor {154    void operator()(A&) {}155  };156  std::variant<A> v;157 158  v.visit(Visitor{});159}160 161struct MyVariant : std::variant<short, long, float> {};162 163// FIXME: This is UB according to [namespace.std]164namespace std {165template <std::size_t Index>166void get(const MyVariant&) {167  assert(false);168}169} // namespace std170 171void test_derived_from_variant() {172  auto v1        = MyVariant{42};173  const auto cv1 = MyVariant{142};174 175  v1.visit([](auto x) { assert(x == 42); });176  cv1.visit([](auto x) { assert(x == 142); });177  MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); });178  std::move(v1).visit([](auto x) { assert(x == 42); });179  std::move(cv1).visit([](auto x) { assert(x == 142); });180 181  // Check that visit does not take index nor valueless_by_exception members from the base class.182  struct EvilVariantBase {183    int index;184    char valueless_by_exception;185  };186 187  struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {188    using std::variant<int, long, double>::variant;189  };190 191  EvilVariant1{12}.visit([](auto x) { assert(x == 12); });192  EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); });193 194  // Check that visit unambiguously picks the variant, even if the other base has __impl member.195  struct ImplVariantBase {196    struct Callable {197      bool operator()() const {198        assert(false);199        return false;200      }201    };202 203    Callable __impl;204  };205 206  struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase {207    using std::variant<int, long, double>::variant;208  };209 210  EvilVariant2{12}.visit([](auto x) { assert(x == 12); });211  EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); });212}213 214int main(int, char**) {215  test_call_operator_forwarding();216  test_argument_forwarding();217  test_return_type();218  test_constexpr();219  test_exceptions();220  test_caller_accepts_nonconst();221  test_derived_from_variant();222 223  return 0;224}225