Implement LWG issue 2219 - support reference_wrapper in INVOKE

llvm-svn: 266590
diff --git a/libcxx/test/std/utilities/function.objects/func.invoke/invoke.pass.cpp b/libcxx/test/std/utilities/function.objects/func.invoke/invoke.pass.cpp
index 97b0b4d..3f02c7c 100644
--- a/libcxx/test/std/utilities/function.objects/func.invoke/invoke.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.invoke/invoke.pass.cpp
@@ -174,6 +174,32 @@
     }
     {
         TestClass cl_obj(42);
+        std::reference_wrapper<TestClass> cl(cl_obj);
+        test_b12<int&(NonCopyable&&) &, int&>(cl);
+        test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
+        test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
+        test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
+
+        test_b12<int&(NonCopyable&&) &, int&>(std::move(cl));
+        test_b12<int const&(NonCopyable&&) const &, int const&>(std::move(cl));
+        test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(std::move(cl));
+        test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(std::move(cl));
+    }
+    {
+        DerivedFromTestClass cl_obj(42);
+        std::reference_wrapper<DerivedFromTestClass> cl(cl_obj);
+        test_b12<int&(NonCopyable&&) &, int&>(cl);
+        test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
+        test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
+        test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
+
+        test_b12<int&(NonCopyable&&) &, int&>(std::move(cl));
+        test_b12<int const&(NonCopyable&&) const &, int const&>(std::move(cl));
+        test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(std::move(cl));
+        test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(std::move(cl));
+    }
+    {
+        TestClass cl_obj(42);
         TestClass *cl = &cl_obj;
         test_b12<int&(NonCopyable&&) &, int&>(cl);
         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
@@ -219,6 +245,22 @@
     }
     {
         typedef TestClass Fn;
+        Fn cl(42);
+        test_b34<int&>(std::reference_wrapper<Fn>(cl));
+        test_b34<int const&>(std::reference_wrapper<Fn const>(cl));
+        test_b34<int volatile&>(std::reference_wrapper<Fn volatile>(cl));
+        test_b34<int const volatile&>(std::reference_wrapper<Fn const volatile>(cl));
+    }
+    {
+        typedef DerivedFromTestClass Fn;
+        Fn cl(42);
+        test_b34<int&>(std::reference_wrapper<Fn>(cl));
+        test_b34<int const&>(std::reference_wrapper<Fn const>(cl));
+        test_b34<int volatile&>(std::reference_wrapper<Fn volatile>(cl));
+        test_b34<int const volatile&>(std::reference_wrapper<Fn const volatile>(cl));
+    }
+    {
+        typedef TestClass Fn;
         Fn cl_obj(42);
         Fn* cl = &cl_obj;
         test_b34<int&>(cl);
diff --git a/libcxx/test/std/utilities/function.objects/func.require/bullet_1_and_2.pass.cpp b/libcxx/test/std/utilities/function.objects/func.require/bullet_1_2_3.pass.cpp
similarity index 86%
rename from libcxx/test/std/utilities/function.objects/func.require/bullet_1_and_2.pass.cpp
rename to libcxx/test/std/utilities/function.objects/func.require/bullet_1_2_3.pass.cpp
index e579f20..09e8e21 100644
--- a/libcxx/test/std/utilities/function.objects/func.require/bullet_1_and_2.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.require/bullet_1_2_3.pass.cpp
@@ -14,12 +14,14 @@
 //------------------------------------------------------------------------------
 // TESTING INVOKE(f, t1, t2, ..., tN)
 //   - Bullet 1 -- (t1.*f)(t2, ..., tN)
-//   - Bullet 2 -- ((*t1).*f)(t2, ..., tN)
+//   - Bullet 2 -- (t1.get().*f)(t2, ..., tN) // t1 is a reference_wrapper
+//   - Bullet 3 -- ((*t1).*f)(t2, ..., tN)
 //
 // Overview:
-//    Bullets 1 and 2 handle the case where 'f' is a pointer to member function.
+//    Bullets 1, 2 and 3 handle the case where 'f' is a pointer to member function.
 //    Bullet 1 only handles the cases where t1 is an object of type T or a
-//    type derived from 'T'. Bullet 2 handles all other cases.
+//    type derived from 'T'. Bullet 2 handles the case where 't1' is a reference
+//    wrapper and bullet 3 handles all other cases.
 //
 // Concerns:
 //   1) cv-qualified member function signatures are accepted.
@@ -31,6 +33,7 @@
 //      as the call object.
 //   7) Pointers to T or a type derived from T can be used as the call object.
 //   8) Reference return types are properly deduced.
+//   9) reference_wrappers are properly handled and unwrapped.
 //
 //
 // Plan:
@@ -123,6 +126,7 @@
 #endif // TEST_STD_VER >= 11
 
 
+
 //==============================================================================
 // TestCase - A test case for a single member function.
 //   ClassType - The type of the class being tested.
@@ -151,6 +155,8 @@
         D* der_ptr = &der;
         DerefToType<T>   dref;
         DerefPropType<T> dref2;
+        std::reference_wrapper<T> rref(obj);
+        std::reference_wrapper<D> drref(der);
 
          // (Plan-3) Dispatch based on the CV tags.
         CV tag;
@@ -158,9 +164,13 @@
         runTestDispatch(tag,  obj);
         runTestDispatch(tag,  der);
         runTestDispatch(tag, dref2);
-        runTestDispatchIf(NotRValue, tag,  dref);
-        runTestDispatchIf(NotRValue, tag,  obj_ptr);
+        runTestDispatchIf(NotRValue, tag, dref);
+        runTestDispatchIf(NotRValue, tag, obj_ptr);
         runTestDispatchIf(NotRValue, tag, der_ptr);
+#if TEST_STD_VER >= 11
+        runTestDispatchIf(NotRValue, tag, rref);
+        runTestDispatchIf(NotRValue, tag, drref);
+#endif
     }
 
     template <class QT, class Tp>
@@ -179,27 +189,43 @@
 
     template <class Tp>
     void runTestDispatch(Q_Const, Tp& v) {
-        Tp const& cv = v;
         runTest(v);
-        runTest(cv);
+        runTest(makeConst(v));
     }
 
     template <class Tp>
     void runTestDispatch(Q_Volatile, Tp& v) {
-        Tp volatile& vv = v;
         runTest(v);
-        runTest(vv);
+        runTest(makeVolatile(v));
+
     }
 
     template <class Tp>
     void runTestDispatch(Q_CV, Tp& v) {
-        Tp const& cv = v;
-        Tp volatile& vv = v;
-        Tp const volatile& cvv = v;
         runTest(v);
-        runTest(cv);
-        runTest(vv);
-        runTest(cvv);
+        runTest(makeConst(v));
+        runTest(makeVolatile(v));
+        runTest(makeCV(v));
+    }
+
+    template <class T>
+    void runTest(const std::reference_wrapper<T>& obj) {
+        typedef Caster<Q_None, RValue> SCast;
+        typedef Caster<Q_None, ArgRValue> ACast;
+        typedef CallSig (ClassType::*MemPtr);
+        // Delegate test to logic in invoke_helpers.h
+        BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;
+        b.runTest( (MemPtr)&ClassType::f, obj);
+    }
+
+    template <class T>
+    void runTest(T* obj) {
+        typedef Caster<Q_None, RValue> SCast;
+        typedef Caster<Q_None, ArgRValue> ACast;
+        typedef CallSig (ClassType::*MemPtr);
+        // Delegate test to logic in invoke_helpers.h
+        BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;
+        b.runTest( (MemPtr)&ClassType::f, obj);
     }
 
     template <class Obj>
@@ -221,6 +247,27 @@
 struct TestCase11 : public TestCaseImp<MemFun11, Sig, Arity, CV, RValue, true> {};
 #endif
 
+template <class Tp>
+struct DerivedFromRefWrap : public std::reference_wrapper<Tp> {
+  DerivedFromRefWrap(Tp& tp) : std::reference_wrapper<Tp>(tp) {}
+};
+
+#if TEST_STD_VER >= 11
+void test_derived_from_ref_wrap() {
+    int x = 42;
+    std::reference_wrapper<int> r(x);
+    std::reference_wrapper<std::reference_wrapper<int>> r2(r);
+    DerivedFromRefWrap<int> d(x);
+    auto get_fn = &std::reference_wrapper<int>::get;
+    auto& ret = std::__invoke(get_fn, r);
+    assert(&ret == &x);
+    auto& ret2 = std::__invoke(get_fn, d);
+    assert(&ret2 == &x);
+    auto& ret3 = std::__invoke(get_fn, r2);
+    assert(&ret3 == &x);
+}
+#endif
+
 int main() {
     typedef void*& R;
     typedef ArgType A;
@@ -314,5 +361,7 @@
     TestCase11<R(A&&, A&&, A&&, ...)  const &&,           3, Q_Const, /* RValue */ true>::run();
     TestCase11<R(A&&, A&&, A&&, ...)  volatile &&,        3, Q_Volatile, /* RValue */ true>::run();
     TestCase11<R(A&&, A&&, A&&, ...)  const volatile &&,  3, Q_CV, /* RValue */ true>::run();
+
+    test_derived_from_ref_wrap();
 #endif
 }
\ No newline at end of file
diff --git a/libcxx/test/std/utilities/function.objects/func.require/bullet_3_and_4.pass.cpp b/libcxx/test/std/utilities/function.objects/func.require/bullet_4_5_6.pass.cpp
similarity index 64%
rename from libcxx/test/std/utilities/function.objects/func.require/bullet_3_and_4.pass.cpp
rename to libcxx/test/std/utilities/function.objects/func.require/bullet_4_5_6.pass.cpp
index b6fe190..2007c41 100644
--- a/libcxx/test/std/utilities/function.objects/func.require/bullet_3_and_4.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.require/bullet_4_5_6.pass.cpp
@@ -13,13 +13,15 @@
 
 //------------------------------------------------------------------------------
 // TESTING INVOKE(f, t1, t2, ..., tN)
-//   - Bullet 3 -- t1.*f
-//   - Bullet 4 -- (*t1).*f
+//   - Bullet 4 -- t1.*f
+//   - Bullet 5 -- t1.get().*f // t1 is a reference wrapper.
+//   - Bullet 6 -- (*t1).*f
 //
 // Overview:
-//    Bullets 3 and 4 handle the case where 'f' is a pointer to member object.
-//    Bullet 3 only handles the cases where t1 is an object of type T or a
-//    type derived from 'T'. Bullet 4 handles all other cases.
+//    Bullets 4, 5 and 6 handle the case where 'f' is a pointer to member object.
+//    Bullet 4 only handles the cases where t1 is an object of type T or a
+//    type derived from 'T'. Bullet 5 handles cases where 't1' is a reference_wrapper
+//     and bullet 6 handles all other cases.
 //
 // Concerns:
 //   1) The return type is always an lvalue reference.
@@ -30,6 +32,7 @@
 //   6) All types that dereference to T or a type derived from T can be used
 //      as the call object.
 //   7) Pointers to T or a type derived from T can be used as the call object.
+//   8) reference_wrapper's are properly unwrapped before invoking the function.
 
 #include <functional>
 #include <type_traits>
@@ -66,6 +69,8 @@
         Derived* der_ptr = &der;
         DerefToType<TestType>   dref;
         DerefPropType<TestType> dref2;
+        std::reference_wrapper<TestType> rref(obj);
+        std::reference_wrapper<Derived> drref(der);
 
         {
             typedef ObjectType (TestType::*MemPtr);
@@ -74,9 +79,13 @@
             runTestDispatch<E>(M, obj, &obj.object);
             runTestDispatch<E>(M, der, &der.object);
             runTestDispatch<E>(M, dref2, &dref2.object.object);
-            runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object);
-            runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object);
-            runTestPointerDispatch<E>(M, dref, &dref.object.object);
+            runTestPropCVDispatch<E>(M, obj_ptr, &obj_ptr->object);
+            runTestPropCVDispatch<E>(M, der_ptr, &der_ptr->object);
+#if TEST_STD_VER >= 11
+            runTestPropCVDispatch<E>(M, rref, &(rref.get().object));
+            runTestPropCVDispatch<E>(M, drref, &(drref.get().object));
+#endif
+            runTestNoPropDispatch<E>(M, dref, &dref.object.object);
         }
         {
             typedef ObjectType const (TestType::*CMemPtr);
@@ -85,9 +94,13 @@
             runTestDispatch<E>(M, obj, &obj.object);
             runTestDispatch<E>(M, der, &der.object);
             runTestDispatch<E>(M, dref2, &dref2.object.object);
-            runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object);
-            runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object);
-            runTestPointerDispatch<E>(M, dref, &dref.object.object);
+            runTestPropCVDispatch<E>(M, obj_ptr, &obj_ptr->object);
+            runTestPropCVDispatch<E>(M, der_ptr, &der_ptr->object);
+#if TEST_STD_VER >= 11
+            runTestPropCVDispatch<E>(M, rref, &(rref.get().object));
+            runTestPropCVDispatch<E>(M, drref, &(drref.get().object));
+#endif
+            runTestNoPropDispatch<E>(M, dref,    &dref.object.object);
         }
         {
             typedef ObjectType volatile (TestType::*VMemPtr);
@@ -96,9 +109,13 @@
             runTestDispatch<E>(M, obj,  &obj.object);
             runTestDispatch<E>(M, der,  &der.object);
             runTestDispatch<E>(M, dref2, &dref2.object.object);
-            runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object);
-            runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object);
-            runTestPointerDispatch<E>(M, dref,    &dref.object.object);
+            runTestPropCVDispatch<E>(M, obj_ptr, &obj_ptr->object);
+            runTestPropCVDispatch<E>(M, der_ptr, &der_ptr->object);
+#if TEST_STD_VER >= 11
+            runTestPropCVDispatch<E>(M, rref, &(rref.get().object));
+            runTestPropCVDispatch<E>(M, drref, &(drref.get().object));
+#endif
+            runTestNoPropDispatch<E>(M, dref,    &dref.object.object);
         }
         {
             typedef ObjectType const volatile (TestType::*CVMemPtr);
@@ -107,9 +124,13 @@
             runTestDispatch<E>(M, obj,   &obj.object);
             runTestDispatch<E>(M, der,   &der.object);
             runTestDispatch<E>(M, dref2, &dref2.object.object);
-            runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object);
-            runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object);
-            runTestPointerDispatch<E>(M, dref,    &dref.object.object);
+            runTestPropCVDispatch<E>(M, obj_ptr, &obj_ptr->object);
+            runTestPropCVDispatch<E>(M, der_ptr, &der_ptr->object);
+#if TEST_STD_VER >= 11
+            runTestPropCVDispatch<E>(M, rref, &(rref.get().object));
+            runTestPropCVDispatch<E>(M, drref, &(drref.get().object));
+#endif
+            runTestNoPropDispatch<E>(M, dref,    &dref.object.object);
         }
     }
 
@@ -128,7 +149,15 @@
     }
 
     template <class Expect, class Fn, class T>
-    void runTestPointerDispatch(Fn M, T& obj, ObjectType* expect) {
+    void runTestPropCVDispatch(Fn M, T& obj, ObjectType* expect) {
+        runTest<Expect &>              (M, obj,                     expect);
+        runTest<Expect const&>         (M, makeConst(obj),          expect);
+        runTest<Expect volatile&>      (M, makeVolatile(obj),       expect);
+        runTest<Expect const volatile&>(M, makeCV(obj),             expect);
+    }
+
+    template <class Expect, class Fn, class T>
+    void runTestNoPropDispatch(Fn M, T& obj, ObjectType* expect) {
         runTest<Expect&>(M, C_<T &>(obj),               expect);
         runTest<Expect&>(M, C_<T const&>(obj),          expect);
         runTest<Expect&>(M, C_<T volatile&>(obj),       expect);
@@ -142,6 +171,15 @@
     }
 
     template <class Expect, class Fn, class T>
+    void runTest(Fn M, const T& obj, ObjectType* expect) {
+         static_assert((std::is_same<
+            decltype(std::__invoke(M, obj)), Expect
+          >::value), "");
+        Expect e = std::__invoke(M, obj);
+        assert(&e == expect);
+    }
+
+    template <class Expect, class Fn, class T>
 #if TEST_STD_VER >= 11
     void runTest(Fn M, T&& obj, ObjectType* expect) {
 #else
@@ -155,6 +193,9 @@
     }
 };
 
+
+
+
 int main() {
     TestCase<ArgType>::run();
     TestCase<ArgType const>::run();
diff --git a/libcxx/test/std/utilities/function.objects/func.require/bullet_5.pass.cpp b/libcxx/test/std/utilities/function.objects/func.require/bullet_7.pass.cpp
similarity index 99%
rename from libcxx/test/std/utilities/function.objects/func.require/bullet_5.pass.cpp
rename to libcxx/test/std/utilities/function.objects/func.require/bullet_7.pass.cpp
index 3f3c96a..0d14a35 100644
--- a/libcxx/test/std/utilities/function.objects/func.require/bullet_5.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.require/bullet_7.pass.cpp
@@ -13,10 +13,10 @@
 
 //------------------------------------------------------------------------------
 // TESTING INVOKE(f, t1, t2, ..., tN)
-//   - Bullet 5 -- f(t2, ..., tN)
+//   - Bullet 7 -- f(t2, ..., tN)
 //
 // Overview:
-//    Bullet 5 handles the cases where the first argument is not a member
+//    Bullet 7 handles the cases where the first argument is not a member
 //   function.
 //
 // Concerns:
diff --git a/libcxx/test/std/utilities/function.objects/func.require/invoke_helpers.h b/libcxx/test/std/utilities/function.objects/func.require/invoke_helpers.h
index a85b39f..495703d 100644
--- a/libcxx/test/std/utilities/function.objects/func.require/invoke_helpers.h
+++ b/libcxx/test/std/utilities/function.objects/func.require/invoke_helpers.h
@@ -79,6 +79,40 @@
 typedef Caster<Q_Volatile, true> MoveVolatileCaster;
 typedef Caster<Q_CV,       true> MoveCVCaster;
 
+
+template <class Tp>
+Tp const& makeConst(Tp& ref) { return ref; }
+
+template <class Tp>
+Tp const* makeConst(Tp* ptr) { return ptr; }
+
+template <class Tp>
+std::reference_wrapper<const Tp> makeConst(std::reference_wrapper<Tp>& ref) {
+    return std::reference_wrapper<const Tp>(ref.get());
+}
+
+template <class Tp>
+Tp volatile& makeVolatile(Tp& ref) { return ref; }
+
+template <class Tp>
+Tp volatile* makeVolatile(Tp* ptr) { return ptr; }
+
+template <class Tp>
+std::reference_wrapper<volatile Tp> makeVolatile(std::reference_wrapper<Tp>& ref) {
+    return std::reference_wrapper<volatile Tp>(ref.get());
+}
+
+template <class Tp>
+Tp const volatile& makeCV(Tp& ref) { return ref; }
+
+template <class Tp>
+Tp const volatile* makeCV(Tp* ptr) { return ptr; }
+
+template <class Tp>
+std::reference_wrapper<const volatile Tp> makeCV(std::reference_wrapper<Tp>& ref) {
+    return std::reference_wrapper<const volatile Tp>(ref.get());
+}
+
 // A shorter name for 'static_cast'
 template <class QualType, class Tp>
 QualType C_(Tp& v) { return static_cast<QualType>(v); };