visit.pass.cpp 8.7 KB

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