diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.csv @@ -280,7 +280,7 @@ "`3622 `__","Misspecified transitivity of equivalence in ยง[unord.req.general]","February 2023","","","" "`3631 `__","``basic_format_arg(T&&)`` should use ``remove_cvref_t`` throughout","February 2023","|Complete|","17.0","" "`3645 `__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0","" -"`3655 `__","The ``INVOKE`` operation and union types","February 2023","","","" +"`3655 `__","The ``INVOKE`` operation and union types","February 2023","|Complete|","18.0","" "`3723 `__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|" "`3734 `__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","","","" "`3772 `__","``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 --- a/libcxx/include/__type_traits/invoke.h +++ b/libcxx/include/__type_traits/invoke.h @@ -240,7 +240,8 @@ class _DecayA0 = __decay_t<_A0>, class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> using __enable_if_bullet1 = - __enable_if_t::value && is_base_of<_ClassT, _DecayA0>::value>; + __enable_if_t::value && + (is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value)>; template , class _DecayA0 = __decay_t<_A0> > using __enable_if_bullet2 = @@ -252,7 +253,8 @@ class _DecayA0 = __decay_t<_A0>, class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> using __enable_if_bullet3 = - __enable_if_t::value && !is_base_of<_ClassT, _DecayA0>::value && + __enable_if_t::value && + !(is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value) && !__is_reference_wrapper<_DecayA0>::value>; template , class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> using __enable_if_bullet4 = - __enable_if_t::value && is_base_of<_ClassT, _DecayA0>::value>; + __enable_if_t::value && + (is_same<_ClassT, _DecayA0>::value || is_base_of<_ClassT, _DecayA0>::value)>; template , class _DecayA0 = __decay_t<_A0> > using __enable_if_bullet5 = @@ -273,7 +276,8 @@ class _DecayA0 = __decay_t<_A0>, class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> using __enable_if_bullet6 = - __enable_if_t::value && !is_base_of<_ClassT, _DecayA0>::value && + __enable_if_t::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 --- 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 @@ } } +// 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); + static_assert(!std::is_invocable_v); + } + + { + 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();