brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.9 KiB · a72dcf1 Raw
408 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// template <class Visitor, class... Variants>13// constexpr see below visit(Visitor&& vis, Variants&&... vars);14 15#include <cassert>16#include <memory>17#include <string>18#include <tuple>19#include <type_traits>20#include <utility>21#include <variant>22 23#include "test_macros.h"24#include "variant_test_helpers.h"25 26void test_call_operator_forwarding() {27  using Fn = ForwardingCallObject;28  Fn obj{};29  const Fn &cobj = obj;30  { // test call operator forwarding - no variant31    std::visit(obj);32    assert(Fn::check_call<>(CT_NonConst | CT_LValue));33    std::visit(cobj);34    assert(Fn::check_call<>(CT_Const | CT_LValue));35    std::visit(std::move(obj));36    assert(Fn::check_call<>(CT_NonConst | CT_RValue));37    std::visit(std::move(cobj));38    assert(Fn::check_call<>(CT_Const | CT_RValue));39  }40  { // test call operator forwarding - single variant, single arg41    using V = std::variant<int>;42    V v(42);43    std::visit(obj, v);44    assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));45    std::visit(cobj, v);46    assert(Fn::check_call<int &>(CT_Const | CT_LValue));47    std::visit(std::move(obj), v);48    assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));49    std::visit(std::move(cobj), v);50    assert(Fn::check_call<int &>(CT_Const | CT_RValue));51  }52  { // test call operator forwarding - single variant, multi arg53    using V = std::variant<int, long, double>;54    V v(42l);55    std::visit(obj, v);56    assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));57    std::visit(cobj, v);58    assert(Fn::check_call<long &>(CT_Const | CT_LValue));59    std::visit(std::move(obj), v);60    assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));61    std::visit(std::move(cobj), v);62    assert(Fn::check_call<long &>(CT_Const | CT_RValue));63  }64  { // test call operator forwarding - multi variant, multi arg65    using V = std::variant<int, long, double>;66    using V2 = std::variant<int *, std::string>;67    V v(42l);68    V2 v2("hello");69    std::visit(obj, v, v2);70    assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));71    std::visit(cobj, v, v2);72    assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));73    std::visit(std::move(obj), v, v2);74    assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));75    std::visit(std::move(cobj), v, v2);76    assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));77  }78  {79    using V = std::variant<int, long, double, std::string>;80    V v1(42l), v2("hello"), v3(101), v4(1.1);81    std::visit(obj, v1, v2, v3, v4);82    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue)));83    std::visit(cobj, v1, v2, v3, v4);84    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue)));85    std::visit(std::move(obj), v1, v2, v3, v4);86    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue)));87    std::visit(std::move(cobj), v1, v2, v3, v4);88    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue)));89  }90  {91    using V = std::variant<int, long, double, int*, std::string>;92    V v1(42l), v2("hello"), v3(nullptr), v4(1.1);93    std::visit(obj, v1, v2, v3, v4);94    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue)));95    std::visit(cobj, v1, v2, v3, v4);96    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue)));97    std::visit(std::move(obj), v1, v2, v3, v4);98    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue)));99    std::visit(std::move(cobj), v1, v2, v3, v4);100    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));101  }102}103 104void test_argument_forwarding() {105  using Fn = ForwardingCallObject;106  Fn obj{};107  const auto Val = CT_LValue | CT_NonConst;108  { // single argument - value type109    using V = std::variant<int>;110    V v(42);111    const V &cv = v;112    std::visit(obj, v);113    assert(Fn::check_call<int &>(Val));114    std::visit(obj, cv);115    assert(Fn::check_call<const int &>(Val));116    std::visit(obj, std::move(v));117    assert(Fn::check_call<int &&>(Val));118    std::visit(obj, std::move(cv));119    assert(Fn::check_call<const int &&>(Val));120  }121  { // multi argument - multi variant122    using V = std::variant<int, std::string, long>;123    V v1(42), v2("hello"), v3(43l);124    std::visit(obj, v1, v2, v3);125    assert((Fn::check_call<int &, std::string &, long &>(Val)));126    std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));127    assert((Fn::check_call<const int &, const std::string &, long &&>(Val)));128  }129  {130    using V = std::variant<int, long, double, std::string>;131    V v1(42l), v2("hello"), v3(101), v4(1.1);132    std::visit(obj, v1, v2, v3, v4);133    assert((Fn::check_call<long &, std::string &, int &, double &>(Val)));134    std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));135    assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val)));136  }137  {138    using V = std::variant<int, long, double, int*, std::string>;139    V v1(42l), v2("hello"), v3(nullptr), v4(1.1);140    std::visit(obj, v1, v2, v3, v4);141    assert((Fn::check_call<long &, std::string &, int *&, double &>(Val)));142    std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));143    assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val)));144  }145}146 147void test_return_type() {148  using Fn = ForwardingCallObject;149  Fn obj{};150  const Fn &cobj = obj;151  { // test call operator forwarding - no variant152    static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);153    static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);154    static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);155    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);156  }157  { // test call operator forwarding - single variant, single arg158    using V = std::variant<int>;159    V v(42);160    static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);161    static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);162    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);163    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);164  }165  { // test call operator forwarding - single variant, multi arg166    using V = std::variant<int, long, double>;167    V v(42l);168    static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);169    static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);170    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);171    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);172  }173  { // test call operator forwarding - multi variant, multi arg174    using V = std::variant<int, long, double>;175    using V2 = std::variant<int *, std::string>;176    V v(42l);177    V2 v2("hello");178    static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);179    static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);180    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);181    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);182  }183  {184    using V = std::variant<int, long, double, std::string>;185    V v1(42l), v2("hello"), v3(101), v4(1.1);186    static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);187    static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);188    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);189    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);190  }191  {192    using V = std::variant<int, long, double, int*, std::string>;193    V v1(42l), v2("hello"), v3(nullptr), v4(1.1);194    static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);195    static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);196    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);197    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);198  }199}200 201void test_constexpr() {202  constexpr ReturnFirst obj{};203  constexpr ReturnArity aobj{};204  {205    using V = std::variant<int>;206    constexpr V v(42);207    static_assert(std::visit(obj, v) == 42, "");208  }209  {210    using V = std::variant<short, long, char>;211    constexpr V v(42l);212    static_assert(std::visit(obj, v) == 42, "");213  }214  {215    using V1 = std::variant<int>;216    using V2 = std::variant<int, char *, long long>;217    using V3 = std::variant<bool, int, int>;218    constexpr V1 v1;219    constexpr V2 v2(nullptr);220    constexpr V3 v3;221    static_assert(std::visit(aobj, v1, v2, v3) == 3, "");222  }223  {224    using V1 = std::variant<int>;225    using V2 = std::variant<int, char *, long long>;226    using V3 = std::variant<void *, int, int>;227    constexpr V1 v1;228    constexpr V2 v2(nullptr);229    constexpr V3 v3;230    static_assert(std::visit(aobj, v1, v2, v3) == 3, "");231  }232  {233    using V = std::variant<int, long, double, int *>;234    constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);235    static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");236  }237  {238    using V = std::variant<int, long, double, long long, int *>;239    constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);240    static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");241  }242}243 244void test_exceptions() {245#ifndef TEST_HAS_NO_EXCEPTIONS246  ReturnArity obj{};247  auto test = [&](auto &&... args) {248    try {249      std::visit(obj, args...);250    } catch (const std::bad_variant_access &) {251      return true;252    } catch (...) {253    }254    return false;255  };256  {257    using V = std::variant<int, MakeEmptyT>;258    V v;259    makeEmpty(v);260    assert(test(v));261  }262  {263    using V = std::variant<int, MakeEmptyT>;264    using V2 = std::variant<long, std::string, void *>;265    V v;266    makeEmpty(v);267    V2 v2("hello");268    assert(test(v, v2));269  }270  {271    using V = std::variant<int, MakeEmptyT>;272    using V2 = std::variant<long, std::string, void *>;273    V v;274    makeEmpty(v);275    V2 v2("hello");276    assert(test(v2, v));277  }278  {279    using V = std::variant<int, MakeEmptyT>;280    using V2 = std::variant<long, std::string, void *, MakeEmptyT>;281    V v;282    makeEmpty(v);283    V2 v2;284    makeEmpty(v2);285    assert(test(v, v2));286  }287  {288    using V = std::variant<int, long, double, MakeEmptyT>;289    V v1(42l), v2(101), v3(202), v4(1.1);290    makeEmpty(v1);291    assert(test(v1, v2, v3, v4));292  }293  {294    using V = std::variant<int, long, double, long long, MakeEmptyT>;295    V v1(42l), v2(101), v3(202), v4(1.1);296    makeEmpty(v1);297    makeEmpty(v2);298    makeEmpty(v3);299    makeEmpty(v4);300    assert(test(v1, v2, v3, v4));301  }302#endif303}304 305// See https://llvm.org/PR31916306void test_caller_accepts_nonconst() {307  struct A {};308  struct Visitor {309    void operator()(A&) {}310  };311  std::variant<A> v;312  std::visit(Visitor{}, v);313}314 315struct MyVariant : std::variant<short, long, float> {};316 317// FIXME: This is UB according to [namespace.std]318namespace std {319template <std::size_t Index>320void get(const MyVariant&) {321  assert(false);322}323} // namespace std324 325void test_derived_from_variant() {326  auto v1 = MyVariant{42};327  const auto cv1 = MyVariant{142};328  std::visit([](auto x) { assert(x == 42); }, v1);329  std::visit([](auto x) { assert(x == 142); }, cv1);330  std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});331  std::visit([](auto x) { assert(x == 42); }, std::move(v1));332  std::visit([](auto x) { assert(x == 142); }, std::move(cv1));333 334  // Check that visit does not take index nor valueless_by_exception members from the base class.335  struct EvilVariantBase {336    int index;337    char valueless_by_exception;338  };339 340  struct EvilVariant1 : std::variant<int, long, double>,341                        std::tuple<int>,342                        EvilVariantBase {343    using std::variant<int, long, double>::variant;344  };345 346  std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});347  std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});348 349  // Check that visit unambiguously picks the variant, even if the other base has __impl member.350  struct ImplVariantBase {351    struct Callable {352      bool operator()() const { assert(false); return false; }353    };354 355    Callable __impl;356  };357 358  struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase {359    using std::variant<int, long, double>::variant;360  };361 362  std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});363  std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});364}365 366struct any_visitor {367  template <typename T>368  void operator()(const T&) const {}369};370 371template <typename T, typename = decltype(std::visit(372                          std::declval<any_visitor&>(), std::declval<T>()))>373constexpr bool has_visit(int) {374  return true;375}376 377template <typename T>378constexpr bool has_visit(...) {379  return false;380}381 382void test_sfinae() {383  struct BadVariant : std::variant<short>, std::variant<long, float> {};384  struct BadVariant2 : private std::variant<long, float> {};385  struct GoodVariant : std::variant<long, float> {};386  struct GoodVariant2 : GoodVariant {};387 388  static_assert(!has_visit<int>(0));389  static_assert(!has_visit<BadVariant>(0));390  static_assert(!has_visit<BadVariant2>(0));391  static_assert(has_visit<std::variant<int>>(0));392  static_assert(has_visit<GoodVariant>(0));393  static_assert(has_visit<GoodVariant2>(0));394}395 396int main(int, char**) {397  test_call_operator_forwarding();398  test_argument_forwarding();399  test_return_type();400  test_constexpr();401  test_exceptions();402  test_caller_accepts_nonconst();403  test_derived_from_variant();404  test_sfinae();405 406  return 0;407}408