libcxx

libcxx mirror with random patches
git clone https://git.neptards.moe/neptards/libcxx.git
Log | Files | Refs

visit.pass.cpp (9053B)


      1 // -*- C++ -*-
      2 //===----------------------------------------------------------------------===//
      3 //
      4 //                     The LLVM Compiler Infrastructure
      5 //
      6 // This file is dual licensed under the MIT and the University of Illinois Open
      7 // Source Licenses. See LICENSE.TXT for details.
      8 //
      9 //===----------------------------------------------------------------------===//
     10 
     11 // UNSUPPORTED: c++98, c++03, c++11, c++14
     12 
     13 // XFAIL: availability=macosx10.13
     14 // XFAIL: availability=macosx10.12
     15 // XFAIL: availability=macosx10.11
     16 // XFAIL: availability=macosx10.10
     17 // XFAIL: availability=macosx10.9
     18 // XFAIL: availability=macosx10.8
     19 // XFAIL: availability=macosx10.7
     20 
     21 // <variant>
     22 // template <class Visitor, class... Variants>
     23 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
     24 
     25 #include <cassert>
     26 #include <memory>
     27 #include <string>
     28 #include <type_traits>
     29 #include <utility>
     30 #include <variant>
     31 
     32 #include "test_macros.h"
     33 #include "type_id.h"
     34 #include "variant_test_helpers.hpp"
     35 
     36 enum CallType : unsigned {
     37   CT_None,
     38   CT_NonConst = 1,
     39   CT_Const = 2,
     40   CT_LValue = 4,
     41   CT_RValue = 8
     42 };
     43 
     44 inline constexpr CallType operator|(CallType LHS, CallType RHS) {
     45   return static_cast<CallType>(static_cast<unsigned>(LHS) |
     46                                static_cast<unsigned>(RHS));
     47 }
     48 
     49 struct ForwardingCallObject {
     50 
     51   template <class... Args> bool operator()(Args &&...) & {
     52     set_call<Args &&...>(CT_NonConst | CT_LValue);
     53     return true;
     54   }
     55 
     56   template <class... Args> bool operator()(Args &&...) const & {
     57     set_call<Args &&...>(CT_Const | CT_LValue);
     58     return true;
     59   }
     60 
     61   // Don't allow the call operator to be invoked as an rvalue.
     62   template <class... Args> bool operator()(Args &&...) && {
     63     set_call<Args &&...>(CT_NonConst | CT_RValue);
     64     return true;
     65   }
     66 
     67   template <class... Args> bool operator()(Args &&...) const && {
     68     set_call<Args &&...>(CT_Const | CT_RValue);
     69     return true;
     70   }
     71 
     72   template <class... Args> static void set_call(CallType type) {
     73     assert(last_call_type == CT_None);
     74     assert(last_call_args == nullptr);
     75     last_call_type = type;
     76     last_call_args = std::addressof(makeArgumentID<Args...>());
     77   }
     78 
     79   template <class... Args> static bool check_call(CallType type) {
     80     bool result = last_call_type == type && last_call_args &&
     81                   *last_call_args == makeArgumentID<Args...>();
     82     last_call_type = CT_None;
     83     last_call_args = nullptr;
     84     return result;
     85   }
     86 
     87   static CallType last_call_type;
     88   static const TypeID *last_call_args;
     89 };
     90 
     91 CallType ForwardingCallObject::last_call_type = CT_None;
     92 const TypeID *ForwardingCallObject::last_call_args = nullptr;
     93 
     94 void test_call_operator_forwarding() {
     95   using Fn = ForwardingCallObject;
     96   Fn obj{};
     97   const Fn &cobj = obj;
     98   { // test call operator forwarding - no variant
     99     std::visit(obj);
    100     assert(Fn::check_call<>(CT_NonConst | CT_LValue));
    101     std::visit(cobj);
    102     assert(Fn::check_call<>(CT_Const | CT_LValue));
    103     std::visit(std::move(obj));
    104     assert(Fn::check_call<>(CT_NonConst | CT_RValue));
    105     std::visit(std::move(cobj));
    106     assert(Fn::check_call<>(CT_Const | CT_RValue));
    107   }
    108   { // test call operator forwarding - single variant, single arg
    109     using V = std::variant<int>;
    110     V v(42);
    111     std::visit(obj, v);
    112     assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
    113     std::visit(cobj, v);
    114     assert(Fn::check_call<int &>(CT_Const | CT_LValue));
    115     std::visit(std::move(obj), v);
    116     assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
    117     std::visit(std::move(cobj), v);
    118     assert(Fn::check_call<int &>(CT_Const | CT_RValue));
    119   }
    120   { // test call operator forwarding - single variant, multi arg
    121     using V = std::variant<int, long, double>;
    122     V v(42l);
    123     std::visit(obj, v);
    124     assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
    125     std::visit(cobj, v);
    126     assert(Fn::check_call<long &>(CT_Const | CT_LValue));
    127     std::visit(std::move(obj), v);
    128     assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
    129     std::visit(std::move(cobj), v);
    130     assert(Fn::check_call<long &>(CT_Const | CT_RValue));
    131   }
    132   { // test call operator forwarding - multi variant, multi arg
    133     using V = std::variant<int, long, double>;
    134     using V2 = std::variant<int *, std::string>;
    135     V v(42l);
    136     V2 v2("hello");
    137     std::visit(obj, v, v2);
    138     assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
    139     std::visit(cobj, v, v2);
    140     assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
    141     std::visit(std::move(obj), v, v2);
    142     assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
    143     std::visit(std::move(cobj), v, v2);
    144     assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
    145   }
    146 }
    147 
    148 void test_argument_forwarding() {
    149   using Fn = ForwardingCallObject;
    150   Fn obj{};
    151   const auto Val = CT_LValue | CT_NonConst;
    152   { // single argument - value type
    153     using V = std::variant<int>;
    154     V v(42);
    155     const V &cv = v;
    156     std::visit(obj, v);
    157     assert(Fn::check_call<int &>(Val));
    158     std::visit(obj, cv);
    159     assert(Fn::check_call<const int &>(Val));
    160     std::visit(obj, std::move(v));
    161     assert(Fn::check_call<int &&>(Val));
    162     std::visit(obj, std::move(cv));
    163     assert(Fn::check_call<const int &&>(Val));
    164   }
    165 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
    166   { // single argument - lvalue reference
    167     using V = std::variant<int &>;
    168     int x = 42;
    169     V v(x);
    170     const V &cv = v;
    171     std::visit(obj, v);
    172     assert(Fn::check_call<int &>(Val));
    173     std::visit(obj, cv);
    174     assert(Fn::check_call<int &>(Val));
    175     std::visit(obj, std::move(v));
    176     assert(Fn::check_call<int &>(Val));
    177     std::visit(obj, std::move(cv));
    178     assert(Fn::check_call<int &>(Val));
    179   }
    180   { // single argument - rvalue reference
    181     using V = std::variant<int &&>;
    182     int x = 42;
    183     V v(std::move(x));
    184     const V &cv = v;
    185     std::visit(obj, v);
    186     assert(Fn::check_call<int &>(Val));
    187     std::visit(obj, cv);
    188     assert(Fn::check_call<int &>(Val));
    189     std::visit(obj, std::move(v));
    190     assert(Fn::check_call<int &&>(Val));
    191     std::visit(obj, std::move(cv));
    192     assert(Fn::check_call<int &&>(Val));
    193   }
    194   { // multi argument - multi variant
    195     using S = const std::string &;
    196     using V = std::variant<int, S, long &&>;
    197     const std::string str = "hello";
    198     long l = 43;
    199     V v1(42);
    200     const V &cv1 = v1;
    201     V v2(str);
    202     const V &cv2 = v2;
    203     V v3(std::move(l));
    204     const V &cv3 = v3;
    205     std::visit(obj, v1, v2, v3);
    206     assert((Fn::check_call<int &, S, long &>(Val)));
    207     std::visit(obj, cv1, cv2, std::move(v3));
    208     assert((Fn::check_call<const int &, S, long &&>(Val)));
    209   }
    210 #endif
    211 }
    212 
    213 struct ReturnFirst {
    214   template <class... Args> constexpr int operator()(int f, Args &&...) const {
    215     return f;
    216   }
    217 };
    218 
    219 struct ReturnArity {
    220   template <class... Args> constexpr int operator()(Args &&...) const {
    221     return sizeof...(Args);
    222   }
    223 };
    224 
    225 void test_constexpr() {
    226   constexpr ReturnFirst obj{};
    227   constexpr ReturnArity aobj{};
    228   {
    229     using V = std::variant<int>;
    230     constexpr V v(42);
    231     static_assert(std::visit(obj, v) == 42, "");
    232   }
    233   {
    234     using V = std::variant<short, long, char>;
    235     constexpr V v(42l);
    236     static_assert(std::visit(obj, v) == 42, "");
    237   }
    238   {
    239     using V1 = std::variant<int>;
    240     using V2 = std::variant<int, char *, long long>;
    241     using V3 = std::variant<bool, int, int>;
    242     constexpr V1 v1;
    243     constexpr V2 v2(nullptr);
    244     constexpr V3 v3;
    245     static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
    246   }
    247   {
    248     using V1 = std::variant<int>;
    249     using V2 = std::variant<int, char *, long long>;
    250     using V3 = std::variant<void *, int, int>;
    251     constexpr V1 v1;
    252     constexpr V2 v2(nullptr);
    253     constexpr V3 v3;
    254     static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
    255   }
    256 }
    257 
    258 void test_exceptions() {
    259 #ifndef TEST_HAS_NO_EXCEPTIONS
    260   ReturnArity obj{};
    261   auto test = [&](auto &&... args) {
    262     try {
    263       std::visit(obj, args...);
    264     } catch (const std::bad_variant_access &) {
    265       return true;
    266     } catch (...) {
    267     }
    268     return false;
    269   };
    270   {
    271     using V = std::variant<int, MakeEmptyT>;
    272     V v;
    273     makeEmpty(v);
    274     assert(test(v));
    275   }
    276   {
    277     using V = std::variant<int, MakeEmptyT>;
    278     using V2 = std::variant<long, std::string, void *>;
    279     V v;
    280     makeEmpty(v);
    281     V2 v2("hello");
    282     assert(test(v, v2));
    283   }
    284   {
    285     using V = std::variant<int, MakeEmptyT>;
    286     using V2 = std::variant<long, std::string, void *>;
    287     V v;
    288     makeEmpty(v);
    289     V2 v2("hello");
    290     assert(test(v2, v));
    291   }
    292   {
    293     using V = std::variant<int, MakeEmptyT>;
    294     using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
    295     V v;
    296     makeEmpty(v);
    297     V2 v2;
    298     makeEmpty(v2);
    299     assert(test(v, v2));
    300   }
    301 #endif
    302 }
    303 
    304 // See https://bugs.llvm.org/show_bug.cgi?id=31916
    305 void test_caller_accepts_nonconst() {
    306   struct A {};
    307   struct Visitor {
    308     void operator()(A&) {}
    309   };
    310   std::variant<A> v;
    311   std::visit(Visitor{}, v);
    312 }
    313 
    314 int main() {
    315   test_call_operator_forwarding();
    316   test_argument_forwarding();
    317   test_constexpr();
    318   test_exceptions();
    319   test_caller_accepts_nonconst();
    320 }