[libcxx-commits] [libcxx] e0ec7a0 - [libcxx/variant] Correctly propagate return type of the visitor.

Michael Park via libcxx-commits libcxx-commits at lists.llvm.org
Mon Aug 17 10:54:52 PDT 2020


Author: Michael Park
Date: 2020-08-17T10:53:59-07:00
New Revision: e0ec7a02064968c7df11713689107148b4efb993

URL: https://github.com/llvm/llvm-project/commit/e0ec7a02064968c7df11713689107148b4efb993
DIFF: https://github.com/llvm/llvm-project/commit/e0ec7a02064968c7df11713689107148b4efb993.diff

LOG: [libcxx/variant] Correctly propagate return type of the visitor.

The tests for it were missing so I've added them.

Reviewed By: #libc, EricWF

Differential Revision: https://reviews.llvm.org/D86006

Added: 
    

Modified: 
    libcxx/include/variant
    libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/variant b/libcxx/include/variant
index 7183ec001fc2..aa1c17e1e5cc 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -595,7 +595,7 @@ struct __base {
   __visit_alt_impl(index_sequence<_Is...>, _Vis&& __vis, _Vs&&... __vs) {
     using __multi = __multi<__uncvref_t<_Vs>::__size()...>;
     constexpr auto __dispatch = [](auto... __is) {
-      return +[](_Vis&& __vis_, _Vs&&... __vs_) {
+      return +[](_Vis&& __vis_, _Vs&&... __vs_) -> decltype(auto) {
         return __invoke_constexpr(
             _VSTD::forward<_Vis>(__vis_),
             __access::__base::__get_alt<decltype(__is)::value>(

diff  --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index fc034071f1c2..0edb83be04d4 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -45,25 +45,28 @@ inline constexpr CallType operator|(CallType LHS, CallType RHS) {
 
 struct ForwardingCallObject {
 
-  template <class... Args> bool operator()(Args &&...) & {
+  template <class... Args>
+  ForwardingCallObject& operator()(Args&&...) & {
     set_call<Args &&...>(CT_NonConst | CT_LValue);
-    return true;
+    return *this;
   }
 
-  template <class... Args> bool operator()(Args &&...) const & {
+  template <class... Args>
+  const ForwardingCallObject& operator()(Args&&...) const & {
     set_call<Args &&...>(CT_Const | CT_LValue);
-    return true;
+    return *this;
   }
 
-  // Don't allow the call operator to be invoked as an rvalue.
-  template <class... Args> bool operator()(Args &&...) && {
+  template <class... Args>
+  ForwardingCallObject&& operator()(Args&&...) && {
     set_call<Args &&...>(CT_NonConst | CT_RValue);
-    return true;
+    return std::move(*this);
   }
 
-  template <class... Args> bool operator()(Args &&...) const && {
+  template <class... Args>
+  const ForwardingCallObject&& operator()(Args&&...) const && {
     set_call<Args &&...>(CT_Const | CT_RValue);
-    return true;
+    return std::move(*this);
   }
 
   template <class... Args> static void set_call(CallType type) {
@@ -239,6 +242,60 @@ void test_argument_forwarding() {
   }
 }
 
+void test_return_type() {
+  using Fn = ForwardingCallObject;
+  Fn obj{};
+  const Fn &cobj = obj;
+  { // test call operator forwarding - no variant
+    static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
+  }
+  { // test call operator forwarding - single variant, single arg
+    using V = std::variant<int>;
+    V v(42);
+    static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+  }
+  { // test call operator forwarding - single variant, multi arg
+    using V = std::variant<int, long, double>;
+    V v(42l);
+    static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+  }
+  { // test call operator forwarding - multi variant, multi arg
+    using V = std::variant<int, long, double>;
+    using V2 = std::variant<int *, std::string>;
+    V v(42l);
+    V2 v2("hello");
+    static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
+  }
+  {
+    using V = std::variant<int, long, double, std::string>;
+    V v1(42l), v2("hello"), v3(101), v4(1.1);
+    static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+  }
+  {
+    using V = std::variant<int, long, double, int*, std::string>;
+    V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+    static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+  }
+}
+
 struct ReturnFirst {
   template <class... Args> constexpr int operator()(int f, Args &&...) const {
     return f;
@@ -368,6 +425,7 @@ void test_caller_accepts_nonconst() {
 int main(int, char**) {
   test_call_operator_forwarding();
   test_argument_forwarding();
+  test_return_type();
   test_constexpr();
   test_exceptions();
   test_caller_accepts_nonconst();


        


More information about the libcxx-commits mailing list