[libcxx-commits] [libcxx] [libc++][RFC] Rewrite CPOs with resolver functions (PR #209104)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Oct 17 03:21:51 PDT 2026


================
@@ -49,18 +51,47 @@ concept __ranges_begin_invocable = !__member_data<_Tp> && __can_borrow<_Tp> && r
   { ranges::begin(__t) } -> contiguous_iterator;
 };
 
-struct __fn {
-  template <__member_data _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const noexcept(noexcept(__t.data())) {
-    return __t.data();
-  }
-
-  template <__ranges_begin_invocable _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
-      noexcept(noexcept(std::to_address(ranges::begin(__t)))) {
-    return std::to_address(ranges::begin(__t));
+struct __fn : _CPO<[]<class _Ep> consteval noexcept {
+  // [range.prim.data]
+
+  // Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E. Then:
+  using _Tp = remove_reference_t<_Ep>;
+
+  // If E is an rvalue and enable_borrowed_range<remove_cv_t<T>> is false, ranges​::​data(E) is ill-formed.
+  if constexpr (is_rvalue_reference_v<_Ep> && !enable_borrowed_range<remove_cv_t<_Tp>>) {
+    return;
+
+    // Otherwise, if T is an array type ([dcl.array]) and remove_all_extents_t<T> is an incomplete type,
+    // ranges​::​data(E) is ill-formed with no diagnostic required.
+  } else if constexpr (is_array_v<_Tp>) {
+    if constexpr (!requires { sizeof(remove_all_extents_t<_Tp>); }) {
+      return;
+    } else {
+      // This is inlined from ranges::begin
+      return [](_Ep __v) noexcept { return __v + 0; };
+    }
+
+    // Otherwise, if auto(t.data()) is a valid expression of pointer to object type,
+    // ranges​::​data(E) is expression-equivalent to auto(t.data()).
+  } else if constexpr (requires(_Tp& __t) {
+                         { _LIBCPP_AUTO_CAST(__t.data()) } -> __ptr_to_object;
+                       }) {
+    return [](_Ep __v) noexcept(noexcept(_LIBCPP_AUTO_CAST(__v.data()))) { return _LIBCPP_AUTO_CAST(__v.data()); };
+
+    // Otherwise, if ranges​::​begin(t) is a valid expression whose type models contiguous_iterator,
+    // ranges​::​data(E) is expression-equivalent to to_address(ranges​::​begin(t)).
+  } else if constexpr (requires(_Tp& __t) {
+                         { ranges::begin(__t) } -> contiguous_iterator;
+                       }) {
+    return [](_Ep __v) noexcept(noexcept(std::to_address(ranges::begin(__v)))) {
+      return std::to_address(ranges::begin(__v));
+    };
+
+    // Otherwise, ranges​::​data(E) is ill-formed.
+  } else {
+    return;
----------------
huixie90 wrote:

should we return a diagnostic here? otherwise i would expect the error message is something like void does not have operator()

https://github.com/llvm/llvm-project/pull/209104


More information about the libcxx-commits mailing list