[libcxx-commits] [libcxx] 910b76a - [libc++] Implement LWG-3655: The INVOKE operation and union types

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Sep 21 02:23:46 PDT 2023


Author: Igor Zhukov
Date: 2023-09-21T05:23:41-04:00
New Revision: 910b76a002713414a7249a7ac8eef52aa8eab748

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

LOG: [libc++] Implement LWG-3655: The INVOKE operation and union types

https://cplusplus.github.io/LWG/issue3655

Differential Revision: https://reviews.llvm.org/D144645
Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>

Added: 
    

Modified: 
    libcxx/docs/Status/Cxx23Issues.csv
    libcxx/include/__type_traits/invoke.h
    libcxx/test/std/utilities/function.objects/func.invoke/invoke.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index 20b0fa7fc9d1fcd..67ef35ec39b2a81 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -280,7 +280,7 @@
 "`3622 <https://wg21.link/LWG3622>`__","Misspecified transitivity of equivalence in ยง[unord.req.general]","February 2023","","",""
 "`3631 <https://wg21.link/LWG3631>`__","``basic_format_arg(T&&)`` should use ``remove_cvref_t<T>`` throughout","February 2023","|Complete|","17.0",""
 "`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0",""
-"`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","","",""
+"`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","|Complete|","18.0",""
 "`3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|"
 "`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","","",""
 "`3772 <https://wg21.link/LWG3772>`__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","","","|ranges|"

diff  --git a/libcxx/include/__type_traits/invoke.h b/libcxx/include/__type_traits/invoke.h
index 5368024955799bf..a6463bfa5904228 100644
--- a/libcxx/include/__type_traits/invoke.h
+++ b/libcxx/include/__type_traits/invoke.h
@@ -240,7 +240,8 @@ template <class _Fp,
           class _DecayA0 = __decay_t<_A0>,
           class _ClassT  = typename __member_pointer_class_type<_DecayFp>::type>
 using __enable_if_bullet1 =
-    __enable_if_t<is_member_function_pointer<_DecayFp>::value && is_base_of<_ClassT, _DecayA0>::value>;
+    __enable_if_t<is_member_function_pointer<_DecayFp>::value &&
+                  (is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value)>;
 
 template <class _Fp, class _A0, class _DecayFp = __decay_t<_Fp>, class _DecayA0 = __decay_t<_A0> >
 using __enable_if_bullet2 =
@@ -252,7 +253,8 @@ template <class _Fp,
           class _DecayA0 = __decay_t<_A0>,
           class _ClassT  = typename __member_pointer_class_type<_DecayFp>::type>
 using __enable_if_bullet3 =
-    __enable_if_t<is_member_function_pointer<_DecayFp>::value && !is_base_of<_ClassT, _DecayA0>::value &&
+    __enable_if_t<is_member_function_pointer<_DecayFp>::value &&
+                  !(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value) &&
                   !__is_reference_wrapper<_DecayA0>::value>;
 
 template <class _Fp,
@@ -261,7 +263,8 @@ template <class _Fp,
           class _DecayA0 = __decay_t<_A0>,
           class _ClassT  = typename __member_pointer_class_type<_DecayFp>::type>
 using __enable_if_bullet4 =
-    __enable_if_t<is_member_object_pointer<_DecayFp>::value && is_base_of<_ClassT, _DecayA0>::value>;
+    __enable_if_t<is_member_object_pointer<_DecayFp>::value &&
+                  (is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value)>;
 
 template <class _Fp, class _A0, class _DecayFp = __decay_t<_Fp>, class _DecayA0 = __decay_t<_A0> >
 using __enable_if_bullet5 =
@@ -273,7 +276,8 @@ template <class _Fp,
           class _DecayA0 = __decay_t<_A0>,
           class _ClassT  = typename __member_pointer_class_type<_DecayFp>::type>
 using __enable_if_bullet6 =
-    __enable_if_t<is_member_object_pointer<_DecayFp>::value && !is_base_of<_ClassT, _DecayA0>::value &&
+    __enable_if_t<is_member_object_pointer<_DecayFp>::value &&
+                  !(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value) &&
                   !__is_reference_wrapper<_DecayA0>::value>;
 
 // __invoke forward declarations

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 82849a815e7e330..54499c08ad144bc 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
@@ -346,6 +346,75 @@ void noexcept_test() {
     }
 }
 
+// LWG3655: The INVOKE operation and union types
+void union_tests() {
+    union Union {
+        int x;
+        int f() { return 42; }
+        int g() const { return 52; }
+    };
+
+    // With a data member
+    {
+        auto get = []() -> Union { return Union{.x = 3}; };
+        int result = std::invoke(&Union::x, get());
+        assert(result == 3);
+    }
+    {
+        auto get = []() -> Union const { return Union{.x = 3}; };
+        int result = std::invoke(&Union::x, get());
+        assert(result == 3);
+    }
+    {
+        Union u{3};
+        int& result = std::invoke(&Union::x, u);
+        assert(&result == &u.x);
+    }
+    {
+        Union const u{3};
+        int const& result = std::invoke(&Union::x, u);
+        assert(&result == &u.x);
+    }
+
+    // With a pointer to a member function
+    {
+        auto get = []() -> Union { return Union{.x = 3}; };
+        int result = std::invoke(&Union::f, get());
+        assert(result == 42);
+    }
+    {
+        Union u{3};
+        int result = std::invoke(&Union::f, u);
+        assert(result == 42);
+    }
+    {
+        // constness mismatch
+        static_assert(!std::is_invocable_v<int (Union::*)(), Union const>);
+        static_assert(!std::is_invocable_v<int (Union::*)(), Union const&>);
+    }
+
+    {
+        auto get = []() -> Union { return Union{.x = 3}; };
+        int result = std::invoke(&Union::g, get());
+        assert(result == 52);
+    }
+    {
+        auto get = []() -> Union const { return Union{.x = 3}; };
+        int result = std::invoke(&Union::g, get());
+        assert(result == 52);
+    }
+    {
+        Union u{3};
+        int result = std::invoke(&Union::g, u);
+        assert(result == 52);
+    }
+    {
+        Union const u{3};
+        int result = std::invoke(&Union::g, u);
+        assert(result == 52);
+    }
+}
+
 int main(int, char**) {
     bullet_one_two_tests();
     bullet_three_four_tests();


        


More information about the libcxx-commits mailing list