[libcxx-commits] [libcxx] [libc++] P2602R2 Poison Pills are Too Toxic (PR #74534)

Jakub Mazurkiewicz via libcxx-commits libcxx-commits at lists.llvm.org
Tue Dec 5 15:00:50 PST 2023


https://github.com/JMazurkiewicz created https://github.com/llvm/llvm-project/pull/74534

This PR contains [P2602R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2602r2.html) implemented as a DR in C++20 mode.

>From aaccb9e13618517803df1230741b02b4c5ee08c7 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Tue, 5 Dec 2023 23:36:57 +0100
Subject: [PATCH] [libc++] P2602R2 Poison Pills are Too Toxic

---
 libcxx/docs/FeatureTestMacroTable.rst         |  2 +-
 libcxx/docs/Status/Cxx23Papers.csv            |  2 +-
 libcxx/include/__compare/partial_order.h      |  2 ++
 libcxx/include/__compare/strong_order.h       |  2 ++
 libcxx/include/__compare/weak_order.h         |  2 ++
 libcxx/include/__iterator/iter_move.h         |  2 +-
 libcxx/include/__ranges/access.h              |  6 ++--
 libcxx/include/__ranges/rbegin.h              |  3 +-
 libcxx/include/__ranges/rend.h                |  3 +-
 libcxx/include/__ranges/size.h                |  3 +-
 libcxx/include/version                        |  4 +--
 .../iterator.cust.move/iter_move.pass.cpp     | 11 +++++++
 .../iterator.cust.swap/iter_swap.pass.cpp     |  6 ++++
 .../ordinary_unqualified_lookup_helpers.h     | 33 +++++++++++++++++++
 .../cmp/cmp.alg/partial_order.pass.cpp        |  9 +++++
 .../cmp/cmp.alg/strong_order.pass.cpp         |  9 +++++
 .../cmp/cmp.alg/weak_order.pass.cpp           |  9 +++++
 .../algorithm.version.compile.pass.cpp        | 14 ++++----
 .../functional.version.compile.pass.cpp       | 14 ++++----
 .../iterator.version.compile.pass.cpp         | 14 ++++----
 .../memory.version.compile.pass.cpp           | 14 ++++----
 .../ranges.version.compile.pass.cpp           | 14 ++++----
 .../version.version.compile.pass.cpp          | 14 ++++----
 .../std/ranges/range.access/begin.pass.cpp    | 18 +++++++---
 .../test/std/ranges/range.access/end.pass.cpp | 20 +++++++----
 .../ordinary_unqualified_lookup_helpers.h     | 25 ++++++++++++++
 .../std/ranges/range.access/rbegin.pass.cpp   | 18 +++++++---
 .../std/ranges/range.access/rend.pass.cpp     | 20 +++++++----
 .../std/ranges/range.access/size.pass.cpp     |  9 ++++-
 .../generate_feature_test_macro_components.py |  2 +-
 30 files changed, 223 insertions(+), 81 deletions(-)
 create mode 100644 libcxx/test/std/language.support/cmp/cmp.alg/ordinary_unqualified_lookup_helpers.h
 create mode 100644 libcxx/test/std/ranges/range.access/ordinary_unqualified_lookup_helpers.h

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index d09f65b7cadc0..f4788aa574788 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -266,7 +266,7 @@ Status
     --------------------------------------------------- -----------------
     ``__cpp_lib_polymorphic_allocator``                 ``201902L``
     --------------------------------------------------- -----------------
-    ``__cpp_lib_ranges``                                ``202207L``
+    ``__cpp_lib_ranges``                                ``202211L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_remove_cvref``                          ``201711L``
     --------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index e03cbff2a08bb..7dc6f36ba1e63 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -100,7 +100,7 @@
 "`P2396R1 <https://wg21.link/P2396R1>`__","LWG", "Concurrency TS 2 fixes ", "November 2022","","","|concurrency TS|"
 "`P2505R5 <https://wg21.link/P2505R5>`__","LWG", "Monadic Functions for ``std::expected``", "November 2022","|Complete|","17.0",""
 "`P2539R4 <https://wg21.link/P2539R4>`__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","|In Progress|","","|format|"
-"`P2602R2 <https://wg21.link/P2602R2>`__","LWG", "Poison Pills are Too Toxic", "November 2022","","","|ranges|"
+"`P2602R2 <https://wg21.link/P2602R2>`__","LWG", "Poison Pills are Too Toxic", "November 2022","|Complete|","18.0","|ranges|"
 "`P2708R1 <https://wg21.link/P2708R1>`__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","",""
 "","","","","","",""
 "`P0290R4 <https://wg21.link/P0290R4>`__","LWG", "``apply()`` for ``synchronized_value<T>``","February 2023","","","|concurrency TS|"
diff --git a/libcxx/include/__compare/partial_order.h b/libcxx/include/__compare/partial_order.h
index 36a11dfaa2881..b422bdd4ef841 100644
--- a/libcxx/include/__compare/partial_order.h
+++ b/libcxx/include/__compare/partial_order.h
@@ -28,6 +28,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // [cmp.alg]
 namespace __partial_order {
+    void partial_order() = delete;
+
     struct __fn {
     // NOLINTBEGIN(libcpp-robust-against-adl) partial_order should use ADL, but only here
         template<class _Tp, class _Up>
diff --git a/libcxx/include/__compare/strong_order.h b/libcxx/include/__compare/strong_order.h
index cbfcf7316de9e..ba59cb51b86d9 100644
--- a/libcxx/include/__compare/strong_order.h
+++ b/libcxx/include/__compare/strong_order.h
@@ -34,6 +34,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // [cmp.alg]
 namespace __strong_order {
+    void strong_order() = delete;
+
     struct __fn {
     // NOLINTBEGIN(libcpp-robust-against-adl) strong_order should use ADL, but only here
         template<class _Tp, class _Up>
diff --git a/libcxx/include/__compare/weak_order.h b/libcxx/include/__compare/weak_order.h
index e6a42ac4c9235..8d7f939092303 100644
--- a/libcxx/include/__compare/weak_order.h
+++ b/libcxx/include/__compare/weak_order.h
@@ -28,6 +28,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // [cmp.alg]
 namespace __weak_order {
+    void weak_order() = delete;
+
     struct __fn {
     // NOLINTBEGIN(libcpp-robust-against-adl) weak_order should use ADL, but only here
         template<class _Tp, class _Up>
diff --git a/libcxx/include/__iterator/iter_move.h b/libcxx/include/__iterator/iter_move.h
index d9ff90bf65456..79dcac8f50b9f 100644
--- a/libcxx/include/__iterator/iter_move.h
+++ b/libcxx/include/__iterator/iter_move.h
@@ -35,7 +35,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 namespace ranges {
 namespace __iter_move {
 
-void iter_move();
+void iter_move() = delete;
 
 template <class _Tp>
 concept __unqualified_iter_move =
diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h
index 502bd5e951c4a..01bf8cc2f544f 100644
--- a/libcxx/include/__ranges/access.h
+++ b/libcxx/include/__ranges/access.h
@@ -49,8 +49,7 @@ namespace __begin {
       { _LIBCPP_AUTO_CAST(__t.begin()) } -> input_or_output_iterator;
     };
 
-  void begin(auto&) = delete;
-  void begin(const auto&) = delete;
+  void begin() = delete;
 
   template <class _Tp>
   concept __unqualified_begin =
@@ -121,8 +120,7 @@ namespace __end {
       { _LIBCPP_AUTO_CAST(__t.end()) } -> sentinel_for<iterator_t<_Tp>>;
     };
 
-  void end(auto&) = delete;
-  void end(const auto&) = delete;
+  void end() = delete;
 
   template <class _Tp>
   concept __unqualified_end =
diff --git a/libcxx/include/__ranges/rbegin.h b/libcxx/include/__ranges/rbegin.h
index 1ceb1116d695f..8fd17a3c016a2 100644
--- a/libcxx/include/__ranges/rbegin.h
+++ b/libcxx/include/__ranges/rbegin.h
@@ -43,8 +43,7 @@ concept __member_rbegin =
     { _LIBCPP_AUTO_CAST(__t.rbegin()) } -> input_or_output_iterator;
   };
 
-void rbegin(auto&) = delete;
-void rbegin(const auto&) = delete;
+void rbegin() = delete;
 
 template <class _Tp>
 concept __unqualified_rbegin =
diff --git a/libcxx/include/__ranges/rend.h b/libcxx/include/__ranges/rend.h
index 7ee574ccfa674..1f482963ac749 100644
--- a/libcxx/include/__ranges/rend.h
+++ b/libcxx/include/__ranges/rend.h
@@ -45,8 +45,7 @@ concept __member_rend =
     { _LIBCPP_AUTO_CAST(__t.rend()) } -> sentinel_for<decltype(ranges::rbegin(__t))>;
   };
 
-void rend(auto&) = delete;
-void rend(const auto&) = delete;
+void rend() = delete;
 
 template <class _Tp>
 concept __unqualified_rend =
diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h
index f22dd1ff7b79f..0ed939e0bd4f9 100644
--- a/libcxx/include/__ranges/size.h
+++ b/libcxx/include/__ranges/size.h
@@ -41,8 +41,7 @@ namespace ranges {
 
 namespace ranges {
 namespace __size {
-void size(auto&) = delete;
-void size(const auto&) = delete;
+void size() = delete;
 
 template <class _Tp>
 concept __size_enabled = !disable_sized_range<remove_cvref_t<_Tp>>;
diff --git a/libcxx/include/version b/libcxx/include/version
index e84790b888d33..71937c3a3d1c2 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -164,7 +164,7 @@ __cpp_lib_parallel_algorithm                            201603L <algorithm> <num
 __cpp_lib_polymorphic_allocator                         201902L <memory_resource>
 __cpp_lib_print                                         202207L <ostream> <print>
 __cpp_lib_quoted_string_io                              201304L <iomanip>
-__cpp_lib_ranges                                        202207L <algorithm> <functional> <iterator>
+__cpp_lib_ranges                                        202211L <algorithm> <functional> <iterator>
                                                                 <memory> <ranges>
 __cpp_lib_ranges_as_const                               202207L <ranges>
 __cpp_lib_ranges_as_rvalue                              202207L <ranges>
@@ -405,7 +405,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 # if _LIBCPP_AVAILABILITY_HAS_PMR
 #   define __cpp_lib_polymorphic_allocator              201902L
 # endif
-# define __cpp_lib_ranges                               202207L
+# define __cpp_lib_ranges                               202211L
 # define __cpp_lib_remove_cvref                         201711L
 # if !defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC
 #   define __cpp_lib_semaphore                          201907L
diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp
index 566638263e887..8cd515d8e7fb4 100644
--- a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp
@@ -11,6 +11,14 @@
 // template<class I>
 // unspecified iter_move;
 
+// Note: this struct is intentionally defined before any other header is included.
+// Custom `iter_move` must be visible to `std::ranges::iter_move` CPO from `<iterator>` header.
+namespace nest {
+struct StructWithGlobalIterMove {};
+} // namespace nest
+
+int&& iter_move(nest::StructWithGlobalIterMove);
+
 #include <algorithm>
 #include <array>
 #include <cassert>
@@ -186,6 +194,9 @@ template<class T> struct Holder { T t; };
 static_assert(std::is_invocable_v<IterMoveT, Holder<Incomplete>**>);
 static_assert(std::is_invocable_v<IterMoveT, Holder<Incomplete>**&>);
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<IterMoveT, nest::StructWithGlobalIterMove&>);
+
 int main(int, char**)
 {
   test();
diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp
index dd78707f25409..692ddef195d2c 100644
--- a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp
@@ -47,6 +47,12 @@ static_assert( std::is_invocable_v<IterSwapT&&, HasIterSwap&, HasIterSwap&>);
 static_assert( std::is_invocable_v<IterSwapT&&, HasIterSwap&, int&>);
 static_assert(!std::is_invocable_v<IterSwapT&&, int&, HasIterSwap&>);
 
+struct NotMoreSpecializedIterSwap {
+  friend void iter_swap(auto&, auto&);
+};
+
+static_assert(!std::is_invocable_v<IterSwapT, NotMoreSpecializedIterSwap&, NotMoreSpecializedIterSwap&>);
+
 struct NodiscardIterSwap {
   [[nodiscard]] friend int iter_swap(NodiscardIterSwap&, NodiscardIterSwap&) { return 0; }
 };
diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/ordinary_unqualified_lookup_helpers.h b/libcxx/test/std/language.support/cmp/cmp.alg/ordinary_unqualified_lookup_helpers.h
new file mode 100644
index 0000000000000..4cbe163c312f4
--- /dev/null
+++ b/libcxx/test/std/language.support/cmp/cmp.alg/ordinary_unqualified_lookup_helpers.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_LANGUAGE_SUPPORT_CMP_CMP_ALG_ORDINARY_UNQUALIFIED_LOOKUP_HELPERS_H
+#define TEST_STD_LANGUAGE_SUPPORT_CMP_CMP_ALG_ORDINARY_UNQUALIFIED_LOOKUP_HELPERS_H
+
+// Note: this header should be included before any other header.
+// Comparison functions defined here must be visible to CPOs from `<compare>` header.
+
+namespace nest {
+struct StructWithGlobalCmpFunctions {};
+} // namespace nest
+
+struct ConvertibleToComparisonType;
+
+ConvertibleToComparisonType strong_order(nest::StructWithGlobalCmpFunctions, nest::StructWithGlobalCmpFunctions);
+ConvertibleToComparisonType weak_order(nest::StructWithGlobalCmpFunctions, nest::StructWithGlobalCmpFunctions);
+ConvertibleToComparisonType partial_order(nest::StructWithGlobalCmpFunctions, nest::StructWithGlobalCmpFunctions);
+
+#include <compare> // Intentionally included here, so we can define `ConvertibleToComparisonType` later.
+
+struct ConvertibleToComparisonType {
+  operator std::strong_ordering() const;
+  operator std::weak_ordering() const;
+  operator std::partial_ordering() const;
+};
+
+#endif // TEST_STD_LANGUAGE_SUPPORT_CMP_CMP_ALG_ORDINARY_UNQUALIFIED_LOOKUP_HELPERS_H
diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp
index bd313889b1a4e..d6376f0a5cb2a 100644
--- a/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp
+++ b/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp
@@ -12,6 +12,10 @@
 
 // template<class T> constexpr partial_ordering partial_order(const T& a, const T& b);
 
+// Note: this header is intentionally included before any other header.
+// Comparison functions defined there must be visible to CPOs from `<compare>` header.
+#include "ordinary_unqualified_lookup_helpers.h"
+
 #include <compare>
 
 #include <cassert>
@@ -240,6 +244,11 @@ constexpr bool test_1_4()
     return true;
 }
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<decltype(std::partial_order),
+                                   nest::StructWithGlobalCmpFunctions,
+                                   nest::StructWithGlobalCmpFunctions>);
+
 int main(int, char**)
 {
     test_1_1();
diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp
index ac6b6879f7730..5c26a0be23f0a 100644
--- a/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp
+++ b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp
@@ -12,6 +12,10 @@
 
 // template<class T> constexpr strong_ordering strong_order(const T& a, const T& b);
 
+// Note: this header is intentionally included before any other header.
+// Comparison functions defined there must be visible to CPOs from `<compare>` header.
+#include "ordinary_unqualified_lookup_helpers.h"
+
 #include <compare>
 
 #include <cassert>
@@ -448,6 +452,11 @@ constexpr bool test_1_4()
     return true;
 }
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<decltype(std::strong_order),
+                                   nest::StructWithGlobalCmpFunctions,
+                                   nest::StructWithGlobalCmpFunctions>);
+
 int main(int, char**)
 {
     test_1_1();
diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp
index 09d720196e0b2..0dc79acc99ed9 100644
--- a/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp
+++ b/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp
@@ -12,6 +12,10 @@
 
 // template<class T> constexpr weak_ordering weak_order(const T& a, const T& b);
 
+// Note: this header is intentionally included before any other header.
+// Comparison functions defined there must be visible to CPOs from `<compare>` header.
+#include "ordinary_unqualified_lookup_helpers.h"
+
 #include <compare>
 
 #include <cassert>
@@ -493,6 +497,11 @@ constexpr bool test_1_5()
     return true;
 }
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<decltype(std::weak_order),
+                                   nest::StructWithGlobalCmpFunctions,
+                                   nest::StructWithGlobalCmpFunctions>);
+
 int main(int, char**)
 {
     test_1_1();
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp
index ec6503ec23755..918c6d35f730d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp
@@ -20,7 +20,7 @@
     __cpp_lib_constexpr_algorithms           201806L [C++20]
     __cpp_lib_freestanding_algorithm         202311L [C++26]
     __cpp_lib_parallel_algorithm             201603L [C++17]
-    __cpp_lib_ranges                         202207L [C++20]
+    __cpp_lib_ranges                         202211L [C++20]
     __cpp_lib_ranges_starts_ends_with        202106L [C++23]
     __cpp_lib_robust_nonmodifying_seq_ops    201304L [C++14]
     __cpp_lib_sample                         201603L [C++17]
@@ -201,8 +201,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++20"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++20"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++20"
 # endif
 
 # ifdef __cpp_lib_ranges_starts_ends_with
@@ -266,8 +266,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++23"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++23"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++23"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
@@ -349,8 +349,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++26"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++26"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++26"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
index 72c96c62b64c4..55674d104fab9 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
@@ -28,7 +28,7 @@
     __cpp_lib_invoke_r                 202106L [C++23]
     __cpp_lib_move_only_function       202110L [C++23]
     __cpp_lib_not_fn                   201603L [C++17]
-    __cpp_lib_ranges                   202207L [C++20]
+    __cpp_lib_ranges                   202211L [C++20]
     __cpp_lib_result_of_sfinae         201210L [C++14]
     __cpp_lib_transparent_operators    201210L [C++14]
                                        201510L [C++17]
@@ -293,8 +293,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++20"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++20"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++20"
 # endif
 
 # ifndef __cpp_lib_result_of_sfinae
@@ -399,8 +399,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++23"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++23"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++23"
 # endif
 
 # ifndef __cpp_lib_result_of_sfinae
@@ -523,8 +523,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++26"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++26"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++26"
 # endif
 
 # ifndef __cpp_lib_result_of_sfinae
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.compile.pass.cpp
index 700907ce9bb07..6c652e694f6dd 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.compile.pass.cpp
@@ -23,7 +23,7 @@
     __cpp_lib_move_iterator_concept         202207L [C++20]
     __cpp_lib_nonmember_container_access    201411L [C++17]
     __cpp_lib_null_iterators                201304L [C++14]
-    __cpp_lib_ranges                        202207L [C++20]
+    __cpp_lib_ranges                        202211L [C++20]
     __cpp_lib_ssize                         201902L [C++20]
 */
 
@@ -197,8 +197,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++20"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++20"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++20"
 # endif
 
 # ifndef __cpp_lib_ssize
@@ -255,8 +255,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++23"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++23"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++23"
 # endif
 
 # ifndef __cpp_lib_ssize
@@ -313,8 +313,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++26"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++26"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++26"
 # endif
 
 # ifndef __cpp_lib_ssize
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
index b1f6c76d84739..8ea1173309432 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
@@ -28,7 +28,7 @@
     __cpp_lib_make_unique                         201304L [C++14]
     __cpp_lib_out_ptr                             202106L [C++23]
                                                   202311L [C++26]
-    __cpp_lib_ranges                              202207L [C++20]
+    __cpp_lib_ranges                              202211L [C++20]
     __cpp_lib_raw_memory_algorithms               201606L [C++17]
     __cpp_lib_shared_ptr_arrays                   201611L [C++17]
                                                   201707L [C++20]
@@ -364,8 +364,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++20"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++20"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++20"
 # endif
 
 # ifndef __cpp_lib_raw_memory_algorithms
@@ -501,8 +501,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++23"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++23"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++23"
 # endif
 
 # ifndef __cpp_lib_raw_memory_algorithms
@@ -638,8 +638,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++26"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++26"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++26"
 # endif
 
 # ifndef __cpp_lib_raw_memory_algorithms
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
index aa3a4964ad492..0ea59178e6878 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
@@ -16,7 +16,7 @@
 // Test the feature test macros defined by <ranges>
 
 /*  Constant                         Value
-    __cpp_lib_ranges                 202207L [C++20]
+    __cpp_lib_ranges                 202211L [C++20]
     __cpp_lib_ranges_as_const        202207L [C++23]
     __cpp_lib_ranges_as_rvalue       202207L [C++23]
     __cpp_lib_ranges_chunk           202202L [C++23]
@@ -162,8 +162,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++20"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++20"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++20"
 # endif
 
 # ifdef __cpp_lib_ranges_as_const
@@ -207,8 +207,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++23"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++23"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++23"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
@@ -309,8 +309,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++26"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++26"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++26"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 0b00469892f60..9572fac59d79f 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -153,7 +153,7 @@
     __cpp_lib_polymorphic_allocator                  201902L [C++20]
     __cpp_lib_print                                  202207L [C++23]
     __cpp_lib_quoted_string_io                       201304L [C++14]
-    __cpp_lib_ranges                                 202207L [C++20]
+    __cpp_lib_ranges                                 202211L [C++20]
     __cpp_lib_ranges_as_const                        202207L [C++23]
     __cpp_lib_ranges_as_rvalue                       202207L [C++23]
     __cpp_lib_ranges_chunk                           202202L [C++23]
@@ -3832,8 +3832,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++20"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++20"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++20"
 # endif
 
 # ifdef __cpp_lib_ranges_as_const
@@ -5272,8 +5272,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++23"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++23"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++23"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
@@ -6985,8 +6985,8 @@
 # ifndef __cpp_lib_ranges
 #   error "__cpp_lib_ranges should be defined in c++26"
 # endif
-# if __cpp_lib_ranges != 202207L
-#   error "__cpp_lib_ranges should have the value 202207L in c++26"
+# if __cpp_lib_ranges != 202211L
+#   error "__cpp_lib_ranges should have the value 202211L in c++26"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp
index ca25fc297a011..89e1e130c2dfb 100644
--- a/libcxx/test/std/ranges/range.access/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp
@@ -11,6 +11,10 @@
 // std::ranges::begin
 // std::ranges::cbegin
 
+// Note: this header is intentionally included before any other header.
+// Access functions defined here must be visible to accessors from `<ranges>` header.
+#include "ordinary_unqualified_lookup_helpers.h"
+
 #include <ranges>
 
 #include <cassert>
@@ -192,7 +196,7 @@ struct BeginFunction {
 };
 static_assert( std::is_invocable_v<RangeBeginT,  BeginFunction const&>);
 static_assert(!std::is_invocable_v<RangeBeginT,  BeginFunction &&>);
-static_assert(!std::is_invocable_v<RangeBeginT,  BeginFunction &>);
+static_assert( std::is_invocable_v<RangeBeginT,  BeginFunction &>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
 static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
 static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
 
@@ -245,7 +249,7 @@ struct BeginFunctionWithPrivateBeginMember {
 constexpr bool testBeginFunction() {
   BeginFunction a{};
   const BeginFunction aa{};
-  static_assert(!std::invocable<RangeBeginT, decltype((a))>);
+  assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::cbegin(a) == &a.x);
   assert(std::ranges::begin(aa) == &aa.x);
   assert(std::ranges::cbegin(aa) == &aa.x);
@@ -266,21 +270,21 @@ constexpr bool testBeginFunction() {
 
   BeginFunctionReturnsEmptyPtr d{};
   const BeginFunctionReturnsEmptyPtr dd{};
-  static_assert(!std::invocable<RangeBeginT, decltype((d))>);
+  assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::cbegin(d) == &d.x);
   assert(std::ranges::begin(dd) == &dd.x);
   assert(std::ranges::cbegin(dd) == &dd.x);
 
   BeginFunctionWithDataMember e{};
   const BeginFunctionWithDataMember ee{};
-  static_assert(!std::invocable<RangeBeginT, decltype((e))>);
+  assert(std::ranges::begin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::begin(ee) == &ee.x);
   assert(std::ranges::cbegin(e) == &e.x);
   assert(std::ranges::cbegin(ee) == &ee.x);
 
   BeginFunctionWithPrivateBeginMember f{};
   const BeginFunctionWithPrivateBeginMember ff{};
-  static_assert(!std::invocable<RangeBeginT, decltype((f))>);
+  assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::cbegin(f) == &f.y);
   assert(std::ranges::begin(ff) == &ff.y);
   assert(std::ranges::cbegin(ff) == &ff.y);
@@ -325,6 +329,10 @@ static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*&>);
 static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
 static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*&>);
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<RangeBeginT, nest::StructWithGlobalAccess&>);
+static_assert(!std::is_invocable_v<RangeCBeginT, nest::StructWithGlobalAccess&>);
+
 int main(int, char**) {
   static_assert(testReturnTypes());
 
diff --git a/libcxx/test/std/ranges/range.access/end.pass.cpp b/libcxx/test/std/ranges/range.access/end.pass.cpp
index 21d97354ef08d..749c20fe4c160 100644
--- a/libcxx/test/std/ranges/range.access/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/end.pass.cpp
@@ -11,6 +11,10 @@
 // std::ranges::end
 // std::ranges::cend
 
+// Note: this header is intentionally included before any other header.
+// Access functions defined here must be visible to accessors from `<ranges>` header.
+#include "ordinary_unqualified_lookup_helpers.h"
+
 #include <ranges>
 
 #include <cassert>
@@ -193,7 +197,7 @@ static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
 
 static_assert( std::is_invocable_v<RangeEndT,  EndFunction const&>);
 static_assert(!std::is_invocable_v<RangeEndT,  EndFunction &&>);
-static_assert(!std::is_invocable_v<RangeEndT,  EndFunction &>);
+static_assert( std::is_invocable_v<RangeEndT,  EndFunction &>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
 static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
 static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
 
@@ -271,7 +275,7 @@ constexpr bool testEndFunction() {
   assert(std::ranges::end(a) == &a.x);
   assert(std::ranges::cend(a) == &a.x);
   EndFunction aa{};
-  static_assert(!std::is_invocable_v<RangeEndT, decltype((aa))>);
+  assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::cend(aa) == &aa.x);
 
   EndFunctionByValue b;
@@ -286,28 +290,28 @@ constexpr bool testEndFunction() {
   assert(std::ranges::end(d) == &d.x);
   assert(std::ranges::cend(d) == &d.x);
   EndFunctionReturnsEmptyPtr dd{};
-  static_assert(!std::is_invocable_v<RangeEndT, decltype((dd))>);
+  assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::cend(dd) == &dd.x);
 
   const EndFunctionWithDataMember e{};
   assert(std::ranges::end(e) == &e.x);
   assert(std::ranges::cend(e) == &e.x);
   EndFunctionWithDataMember ee{};
-  static_assert(!std::is_invocable_v<RangeEndT, decltype((ee))>);
+  assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::cend(ee) == &ee.x);
 
   const EndFunctionWithPrivateEndMember f{};
   assert(std::ranges::end(f) == &f.y);
   assert(std::ranges::cend(f) == &f.y);
   EndFunctionWithPrivateEndMember ff{};
-  static_assert(!std::is_invocable_v<RangeEndT, decltype((ff))>);
+  assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::cend(ff) == &ff.y);
 
   const BeginMemberEndFunction g{};
   assert(std::ranges::end(g) == &g.x);
   assert(std::ranges::cend(g) == &g.x);
   BeginMemberEndFunction gg{};
-  static_assert(!std::is_invocable_v<RangeEndT, decltype((gg))>);
+  assert(std::ranges::end(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::cend(gg) == &gg.x);
 
   return true;
@@ -354,6 +358,10 @@ static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*&>);
 static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);
 static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>);
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<RangeEndT, nest::StructWithGlobalAccess&>);
+static_assert(!std::is_invocable_v<RangeCEndT, nest::StructWithGlobalAccess&>);
+
 int main(int, char**) {
   static_assert(testReturnTypes());
 
diff --git a/libcxx/test/std/ranges/range.access/ordinary_unqualified_lookup_helpers.h b/libcxx/test/std/ranges/range.access/ordinary_unqualified_lookup_helpers.h
new file mode 100644
index 0000000000000..34be68aef1f4f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/ordinary_unqualified_lookup_helpers.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_RANGE_ACCESS_ORDINARY_UNQUALIFIED_LOOKUP_HELPERS_H
+#define TEST_STD_RANGES_RANGE_ACCESS_ORDINARY_UNQUALIFIED_LOOKUP_HELPERS_H
+
+// Note: this header should be included before any other header.
+// Access functions defined here must be visible to accessors from `<ranges>` header.
+
+namespace nest {
+struct StructWithGlobalAccess {};
+} // namespace nest
+
+int* begin(nest::StructWithGlobalAccess);
+int* end(nest::StructWithGlobalAccess);
+int* rbegin(nest::StructWithGlobalAccess);
+int* rend(nest::StructWithGlobalAccess);
+unsigned int size(nest::StructWithGlobalAccess);
+
+#endif // TEST_STD_RANGES_RANGE_ACCESS_ORDINARY_UNQUALIFIED_LOOKUP_HELPERS_H
diff --git a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
index e1a564c94ed94..9bd804b59d3b1 100644
--- a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
@@ -11,6 +11,10 @@
 // std::ranges::rbegin
 // std::ranges::crbegin
 
+// Note: this header is intentionally included before any other header.
+// Access functions defined here must be visible to accessors from `<ranges>` header.
+#include "ordinary_unqualified_lookup_helpers.h"
+
 #include <ranges>
 
 #include <cassert>
@@ -187,7 +191,7 @@ struct RBeginFunction {
 };
 static_assert( std::is_invocable_v<RangeRBeginT,  RBeginFunction const&>);
 static_assert(!std::is_invocable_v<RangeRBeginT,  RBeginFunction &&>);
-static_assert(!std::is_invocable_v<RangeRBeginT,  RBeginFunction &>);
+static_assert( std::is_invocable_v<RangeRBeginT,  RBeginFunction &>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
 static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction const&>);
 static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction &>);
 
@@ -246,7 +250,7 @@ struct RBeginFunctionWithPrivateBeginMember {
 constexpr bool testRBeginFunction() {
   RBeginFunction a{};
   const RBeginFunction aa{};
-  static_assert(!std::invocable<RangeRBeginT, decltype((a))>);
+  assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::crbegin(a) == &a.x);
   assert(std::ranges::rbegin(aa) == &aa.x);
   assert(std::ranges::crbegin(aa) == &aa.x);
@@ -267,21 +271,21 @@ constexpr bool testRBeginFunction() {
 
   RBeginFunctionReturnsEmptyPtr d{};
   const RBeginFunctionReturnsEmptyPtr dd{};
-  static_assert(!std::invocable<RangeRBeginT, decltype((d))>);
+  assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::crbegin(d) == &d.x);
   assert(std::ranges::rbegin(dd) == &dd.x);
   assert(std::ranges::crbegin(dd) == &dd.x);
 
   RBeginFunctionWithDataMember e{};
   const RBeginFunctionWithDataMember ee{};
-  static_assert(!std::invocable<RangeRBeginT, decltype((e))>);
+  assert(std::ranges::rbegin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::rbegin(ee) == &ee.x);
   assert(std::ranges::crbegin(e) == &e.x);
   assert(std::ranges::crbegin(ee) == &ee.x);
 
   RBeginFunctionWithPrivateBeginMember f{};
   const RBeginFunctionWithPrivateBeginMember ff{};
-  static_assert(!std::invocable<RangeRBeginT, decltype((f))>);
+  assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::crbegin(f) == &f.y);
   assert(std::ranges::rbegin(ff) == &ff.y);
   assert(std::ranges::crbegin(ff) == &ff.y);
@@ -501,6 +505,10 @@ static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*&>);
 static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*>);
 static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*&>);
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<RangeRBeginT, nest::StructWithGlobalAccess&>);
+static_assert(!std::is_invocable_v<RangeCRBeginT, nest::StructWithGlobalAccess&>);
+
 int main(int, char**) {
   static_assert(testReturnTypes());
 
diff --git a/libcxx/test/std/ranges/range.access/rend.pass.cpp b/libcxx/test/std/ranges/range.access/rend.pass.cpp
index 5ba244b6b18cf..eb45889ca70f8 100644
--- a/libcxx/test/std/ranges/range.access/rend.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rend.pass.cpp
@@ -11,6 +11,10 @@
 // std::ranges::rend
 // std::ranges::crend
 
+// Note: this header is intentionally included before any other header.
+// Access functions defined here must be visible to accessors from `<ranges>` header.
+#include "ordinary_unqualified_lookup_helpers.h"
+
 #include <ranges>
 
 #include <cassert>
@@ -196,7 +200,7 @@ static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
 
 static_assert( std::is_invocable_v<RangeREndT,  REndFunction const&>);
 static_assert(!std::is_invocable_v<RangeREndT,  REndFunction &&>);
-static_assert(!std::is_invocable_v<RangeREndT,  REndFunction &>);
+static_assert( std::is_invocable_v<RangeREndT,  REndFunction &>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
 static_assert( std::is_invocable_v<RangeCREndT, REndFunction const&>);
 static_assert( std::is_invocable_v<RangeCREndT, REndFunction &>);
 
@@ -272,7 +276,7 @@ constexpr bool testREndFunction() {
   assert(std::ranges::rend(a) == &a.x);
   assert(std::ranges::crend(a) == &a.x);
   REndFunction aa{};
-  static_assert(!std::is_invocable_v<RangeREndT, decltype((aa))>);
+  assert(std::ranges::rend(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::crend(aa) == &aa.x);
 
   REndFunctionByValue b;
@@ -287,28 +291,28 @@ constexpr bool testREndFunction() {
   assert(std::ranges::rend(d) == &d.x);
   assert(std::ranges::crend(d) == &d.x);
   REndFunctionReturnsEmptyPtr dd{};
-  static_assert(!std::is_invocable_v<RangeREndT, decltype((dd))>);
+  assert(std::ranges::rend(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::crend(dd) == &dd.x);
 
   const REndFunctionWithDataMember e{};
   assert(std::ranges::rend(e) == &e.x);
   assert(std::ranges::crend(e) == &e.x);
   REndFunctionWithDataMember ee{};
-  static_assert(!std::is_invocable_v<RangeREndT, decltype((ee))>);
+  assert(std::ranges::rend(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::crend(ee) == &ee.x);
 
   const REndFunctionWithPrivateEndMember f{};
   assert(std::ranges::rend(f) == &f.y);
   assert(std::ranges::crend(f) == &f.y);
   REndFunctionWithPrivateEndMember ff{};
-  static_assert(!std::is_invocable_v<RangeREndT, decltype((ff))>);
+  assert(std::ranges::rend(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::crend(ff) == &ff.y);
 
   const RBeginMemberEndFunction g{};
   assert(std::ranges::rend(g) == &g.x);
   assert(std::ranges::crend(g) == &g.x);
   RBeginMemberEndFunction gg{};
-  static_assert(!std::is_invocable_v<RangeREndT, decltype((gg))>);
+  assert(std::ranges::rend(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
   assert(std::ranges::crend(gg) == &gg.x);
 
   return true;
@@ -530,6 +534,10 @@ static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*&>);
 static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*>);
 static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*&>);
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<RangeREndT, nest::StructWithGlobalAccess&>);
+static_assert(!std::is_invocable_v<RangeCREndT, nest::StructWithGlobalAccess&>);
+
 int main(int, char**) {
   static_assert(testReturnTypes());
 
diff --git a/libcxx/test/std/ranges/range.access/size.pass.cpp b/libcxx/test/std/ranges/range.access/size.pass.cpp
index fd7d0a8b99752..36bd19ba8c579 100644
--- a/libcxx/test/std/ranges/range.access/size.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/size.pass.cpp
@@ -10,6 +10,10 @@
 
 // std::ranges::size
 
+// Note: this header is intentionally included before any other header.
+// Access functions defined here must be visible to accessors from `<ranges>` header.
+#include "ordinary_unqualified_lookup_helpers.h"
+
 #include <ranges>
 
 #include <cassert>
@@ -219,7 +223,7 @@ inline constexpr bool std::ranges::disable_sized_range<const ImproperlyDisabledF
 
 static_assert( std::is_invocable_v<RangeSizeT, ImproperlyDisabledMember&>);
 static_assert( std::is_invocable_v<RangeSizeT, const ImproperlyDisabledMember&>);
-static_assert(!std::is_invocable_v<RangeSizeT, ImproperlyDisabledFunction&>);
+static_assert( std::is_invocable_v<RangeSizeT, ImproperlyDisabledFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
 static_assert( std::is_invocable_v<RangeSizeT, const ImproperlyDisabledFunction&>);
 
 // No begin end.
@@ -318,6 +322,9 @@ template<class T> struct Holder { T t; };
 static_assert(!std::is_invocable_v<RangeSizeT, Holder<Incomplete>*>);
 static_assert(!std::is_invocable_v<RangeSizeT, Holder<Incomplete>*&>);
 
+// Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<RangeSizeT, nest::StructWithGlobalAccess&>);
+
 int main(int, char**) {
   testArrayType();
   static_assert(testArrayType());
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 8943ad2557433..153b7d54a7059 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -882,7 +882,7 @@ def add_version_header(tc):
         },
         {
             "name": "__cpp_lib_ranges",
-            "values": {"c++20": 202207},
+            "values": {"c++20": 202211}, # DR P2602R2 Poison Pills are Too Toxic
             "headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
         },
         {



More information about the libcxx-commits mailing list