mirror of
https://github.com/intel/llvm.git
synced 2026-02-05 13:21:04 +08:00
[libc++] Implement P2538R1 "ADL-proof std::projected" (#65411)
Notice that because Holder<Incomplete> is _possible_ to complete, but _unsafe_ to complete, that means that Holder<Incomplete>* is basically not an iterator and it's not even safe to ask if input_iterator<Holder<Incomplete>*> because that _will_ necessarily complete the type. So it's totally expected that we still cannot safely ask e.g. static_assert(std::indirect_unary_predicate<bool(&)(Holder<Incomplete>&), Holder<Incomplete>*>); or even static_assert(!std::indirect_unary_predicate<int, Holder<Incomplete>*>); This was originally uploaded as https://reviews.llvm.org/D119029 and I picked it up here as part of the Github PR transition. Co-authored-by: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
This commit is contained in:
@@ -51,6 +51,8 @@ Implemented Papers
|
||||
- P2497R0 - Testing for success or failure of ``<charconv>`` functions
|
||||
- P2697R1 - Interfacing ``bitset`` with ``string_view``
|
||||
- P2443R1 - ``views::chunk_by``
|
||||
- P2538R1 - ADL-proof ``std::projected``
|
||||
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
@@ -126,5 +128,9 @@ ABI Affecting Changes
|
||||
and you notice changes to your exported symbols list, then this means that you were not properly preventing libc++
|
||||
symbols from being part of your ABI.
|
||||
|
||||
- The name mangling for intantiations of ``std::projected`` has changed in order to implement P2538R1. This technically
|
||||
results in an ABI break, however in practice we expect uses of ``std::projected`` in ABI-sensitive places to be
|
||||
extremely rare. Any error resulting from this change should result in a link-time error.
|
||||
|
||||
Build System Changes
|
||||
--------------------
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"`P2562R1 <https://wg21.link/P2562R1>`__","LWG","``constexpr`` Stable Sorting","Varna June 2023","","",""
|
||||
"`P2545R4 <https://wg21.link/P2545R4>`__","LWG","Read-Copy Update (RCU)","Varna June 2023","","",""
|
||||
"`P2530R3 <https://wg21.link/P2530R3>`__","LWG","Hazard Pointers for C++26","Varna June 2023","","",""
|
||||
"`P2538R1 <https://wg21.link/P2538R1>`__","LWG","ADL-proof ``std::projected``","Varna June 2023","","","|ranges|"
|
||||
"`P2538R1 <https://wg21.link/P2538R1>`__","LWG","ADL-proof ``std::projected``","Varna June 2023","|Complete|","18.0","|ranges|"
|
||||
"`P2495R3 <https://wg21.link/P2495R3>`__","LWG","Interfacing ``stringstreams`` with ``string_view``","Varna June 2023","","",""
|
||||
"`P2510R3 <https://wg21.link/P2510R3>`__","LWG","Formatting pointers","Varna June 2023","|Complete| [#note-P2510R3]_","17.0","|format|"
|
||||
"`P2198R7 <https://wg21.link/P2198R7>`__","LWG","Freestanding Feature-Test Macros and Implementation-Defined Extensions","Varna June 2023","","",""
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <__config>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/incrementable_traits.h>
|
||||
#include <__iterator/incrementable_traits.h> // iter_difference_t
|
||||
#include <__type_traits/remove_cvref.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
@@ -23,17 +23,29 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
template<indirectly_readable _It, indirectly_regular_unary_invocable<_It> _Proj>
|
||||
struct projected {
|
||||
using value_type = remove_cvref_t<indirect_result_t<_Proj&, _It>>;
|
||||
indirect_result_t<_Proj&, _It> operator*() const; // not defined
|
||||
template <class _It, class _Proj>
|
||||
struct __projected_impl {
|
||||
struct __type {
|
||||
using value_type = remove_cvref_t<indirect_result_t<_Proj&, _It>>;
|
||||
indirect_result_t<_Proj&, _It> operator*() const; // not defined
|
||||
};
|
||||
};
|
||||
|
||||
template<weakly_incrementable _It, class _Proj>
|
||||
struct incrementable_traits<projected<_It, _Proj>> {
|
||||
using difference_type = iter_difference_t<_It>;
|
||||
template <weakly_incrementable _It, class _Proj>
|
||||
struct __projected_impl<_It, _Proj> {
|
||||
struct __type {
|
||||
using value_type = remove_cvref_t<indirect_result_t<_Proj&, _It>>;
|
||||
using difference_type = iter_difference_t<_It>;
|
||||
indirect_result_t<_Proj&, _It> operator*() const; // not defined
|
||||
};
|
||||
};
|
||||
|
||||
// Note that we implement std::projected in a way that satisfies P2538R1 even in standard
|
||||
// modes before C++26 to avoid breaking the ABI between standard modes (even though ABI
|
||||
// breaks with std::projected are expected to have essentially no impact).
|
||||
template <indirectly_readable _It, indirectly_regular_unary_invocable<_It> _Proj>
|
||||
using projected = typename __projected_impl<_It, _Proj>::__type;
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
// template<class F, class I1, class I2>
|
||||
// concept indirect_binary_predicate;
|
||||
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "indirectly_readable.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using It1 = IndirectlyReadable<struct Token1>;
|
||||
using It2 = IndirectlyReadable<struct Token2>;
|
||||
@@ -80,3 +82,11 @@ struct BadPredicate6 {
|
||||
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
|
||||
};
|
||||
static_assert(!std::indirect_binary_predicate<BadPredicate6, It1, It2>);
|
||||
|
||||
// Test ADL-proofing (P2538R1)
|
||||
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
static_assert(std::indirect_binary_predicate<std::less<Holder<Incomplete>*>, Holder<Incomplete>**, Holder<Incomplete>**>);
|
||||
static_assert(!std::indirect_binary_predicate<Holder<Incomplete>*, Holder<Incomplete>**, Holder<Incomplete>**>);
|
||||
#endif
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
// template<class F, class I1, class I2 = I1>
|
||||
// concept indirect_equivalence_relation;
|
||||
|
||||
#include <iterator>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
|
||||
#include "indirectly_readable.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using It1 = IndirectlyReadable<struct Token1>;
|
||||
using It2 = IndirectlyReadable<struct Token2>;
|
||||
@@ -95,3 +97,11 @@ struct BadRelation6 {
|
||||
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
|
||||
};
|
||||
static_assert(!std::indirect_equivalence_relation<BadRelation6, It1, It2>);
|
||||
|
||||
// Test ADL-proofing (P2538R1)
|
||||
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
static_assert(std::indirect_equivalence_relation<std::equal_to<Holder<Incomplete>*>, Holder<Incomplete>**, Holder<Incomplete>**>);
|
||||
static_assert(!std::indirect_equivalence_relation<Holder<Incomplete>*, Holder<Incomplete>**, Holder<Incomplete>**>);
|
||||
#endif
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <iterator>
|
||||
#include <concepts>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
static_assert(std::same_as<std::indirect_result_t<int (*)(int), int*>, int>);
|
||||
static_assert(std::same_as<std::indirect_result_t<double (*)(int const&, float), int const*, float*>, double>);
|
||||
|
||||
@@ -29,3 +31,18 @@ constexpr bool has_indirect_result = requires {
|
||||
|
||||
static_assert(!has_indirect_result<int (*)(int), int>); // int isn't indirectly_readable
|
||||
static_assert(!has_indirect_result<int, int*>); // int isn't invocable
|
||||
|
||||
// Test ADL-proofing (P2538R1)
|
||||
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
|
||||
// TODO: Enable this on GCC once this bug is fixed: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111419
|
||||
#ifndef TEST_COMPILER_GCC
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
static_assert(std::same_as<std::indirect_result_t<int (&)(int), int*>, int>);
|
||||
static_assert(std::same_as<std::indirect_result_t<Holder<Incomplete>&(&)(int), int*>, Holder<Incomplete>&>);
|
||||
static_assert(std::same_as<std::indirect_result_t<Holder<Incomplete>*(&)(int), int*>, Holder<Incomplete>*>);
|
||||
static_assert(std::same_as<std::indirect_result_t<int (&)(Holder<Incomplete>*), Holder<Incomplete>**>, int>);
|
||||
static_assert(std::same_as<std::indirect_result_t<Holder<Incomplete>&(&)(Holder<Incomplete>*), Holder<Incomplete>**>, Holder<Incomplete>&>);
|
||||
static_assert(std::same_as<std::indirect_result_t<Holder<Incomplete>*(&)(Holder<Incomplete>*), Holder<Incomplete>**>, Holder<Incomplete>*>);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
// template<class F, class I1, class I2 = I1>
|
||||
// concept indirect_strict_weak_order;
|
||||
|
||||
#include <iterator>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
|
||||
#include "indirectly_readable.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using It1 = IndirectlyReadable<struct Token1>;
|
||||
using It2 = IndirectlyReadable<struct Token2>;
|
||||
@@ -95,3 +97,11 @@ struct BadOrder6 {
|
||||
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
|
||||
};
|
||||
static_assert(!std::indirect_strict_weak_order<BadOrder6, It1, It2>);
|
||||
|
||||
// Test ADL-proofing (P2538R1)
|
||||
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
static_assert(std::indirect_strict_weak_order<std::less<Holder<Incomplete>*>, Holder<Incomplete>**, Holder<Incomplete>**>);
|
||||
static_assert(!std::indirect_strict_weak_order<Holder<Incomplete>*, Holder<Incomplete>**, Holder<Incomplete>**>);
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <type_traits>
|
||||
|
||||
#include "indirectly_readable.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using It = IndirectlyReadable<struct Token>;
|
||||
|
||||
@@ -62,3 +63,12 @@ struct BadPredicate4 {
|
||||
bool operator()(std::iter_common_reference_t<It>) const = delete;
|
||||
};
|
||||
static_assert(!std::indirect_unary_predicate<BadPredicate4, It>);
|
||||
|
||||
// Test ADL-proofing (P2538R1)
|
||||
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
struct HolderIncompletePred { bool operator()(Holder<Incomplete>*) const; };
|
||||
static_assert(std::indirect_unary_predicate<HolderIncompletePred, Holder<Incomplete>**>);
|
||||
static_assert(!std::indirect_unary_predicate<Holder<Incomplete>*, Holder<Incomplete>**>);
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct Deref {
|
||||
int operator()(int*) const;
|
||||
};
|
||||
@@ -48,3 +50,11 @@ void is_subsumed(F);
|
||||
|
||||
static_assert(subsumes(std::less<int>()));
|
||||
static_assert(is_subsumed(std::less<int>()));
|
||||
|
||||
// Test ADL-proofing (P2538R1)
|
||||
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
static_assert(std::indirectly_comparable<Holder<Incomplete>**, Holder<Incomplete>**, std::less<Holder<Incomplete>*>>);
|
||||
static_assert(!std::indirectly_comparable<Holder<Incomplete>**, Holder<Incomplete>**, Holder<Incomplete>*>);
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <concepts>
|
||||
|
||||
#include "indirectly_readable.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using It = IndirectlyReadable<struct Token>;
|
||||
using R1 = T1<struct ReturnToken>;
|
||||
@@ -85,3 +86,12 @@ static_assert(!std::indirectly_regular_unary_invocable<int (*)(int*, int*), int*
|
||||
static_assert(!std::indirectly_regular_unary_invocable<int (&)(int*, int*), int*>);
|
||||
static_assert(!std::indirectly_regular_unary_invocable<int (S::*)(int*), S*>);
|
||||
static_assert(!std::indirectly_regular_unary_invocable<int (S::*)(int*) const, S*>);
|
||||
|
||||
// Test ADL-proofing (P2538R1)
|
||||
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
struct HolderIncompletePred { bool operator()(Holder<Incomplete>*) const; };
|
||||
static_assert(std::indirectly_regular_unary_invocable<HolderIncompletePred, Holder<Incomplete>**>);
|
||||
static_assert(!std::indirectly_regular_unary_invocable<Holder<Incomplete>*, Holder<Incomplete>**>);
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <concepts>
|
||||
|
||||
#include "indirectly_readable.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using It = IndirectlyReadable<struct Token>;
|
||||
using R1 = T1<struct ReturnToken>;
|
||||
@@ -85,3 +86,12 @@ static_assert(!std::indirectly_unary_invocable<int (*)(int*, int*), int*>);
|
||||
static_assert(!std::indirectly_unary_invocable<int (&)(int*, int*), int*>);
|
||||
static_assert(!std::indirectly_unary_invocable<int (S::*)(int*), S*>);
|
||||
static_assert(!std::indirectly_unary_invocable<int (S::*)(int*) const, S*>);
|
||||
|
||||
// Test ADL-proofing (P2538R1)
|
||||
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
struct HolderIncompletePred { bool operator()(Holder<Incomplete>*) const; };
|
||||
static_assert(std::indirectly_unary_invocable<HolderIncompletePred, Holder<Incomplete>**>);
|
||||
static_assert(!std::indirectly_unary_invocable<Holder<Incomplete>*, Holder<Incomplete>**>);
|
||||
#endif
|
||||
|
||||
@@ -283,7 +283,6 @@ libcxx/include/__iterator/ostreambuf_iterator.h
|
||||
libcxx/include/__iterator/ostream_iterator.h
|
||||
libcxx/include/__iterator/permutable.h
|
||||
libcxx/include/__iterator/prev.h
|
||||
libcxx/include/__iterator/projected.h
|
||||
libcxx/include/__iterator/readable_traits.h
|
||||
libcxx/include/__iterator/reverse_access.h
|
||||
libcxx/include/__iterator/reverse_iterator.h
|
||||
|
||||
Reference in New Issue
Block a user