[libcxx-commits] [libcxx] 308892f - [libc++][ranges] Implement P3052R2: `view_interface::at()` (#205012)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Sep 2 08:33:30 PDT 2026


Author: Hristo Hristov
Date: 2026-09-02T18:33:16+03:00
New Revision: 308892ffc7f2aa1af580b6726297e3d516525488

URL: https://github.com/llvm/llvm-project/commit/308892ffc7f2aa1af580b6726297e3d516525488
DIFF: https://github.com/llvm/llvm-project/commit/308892ffc7f2aa1af580b6726297e3d516525488.diff

LOG: [libc++][ranges] Implement P3052R2: `view_interface::at()` (#205012)

Closes #204395

Implements https://wg21.link/P3052R2

---------

Co-authored-by: Hristo Hristov <zingam at outlook.com>
Co-authored-by: A. Jiang <de34 at live.cn>

Added: 
    

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes/24.rst
    libcxx/docs/Status/Cxx29Papers.csv
    libcxx/include/__ranges/view_interface.h
    libcxx/include/version
    libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
    libcxx/test/libcxx/transitive_includes/cxx20.csv
    libcxx/test/libcxx/transitive_includes/cxx23.csv
    libcxx/test/libcxx/transitive_includes/cxx26.csv
    libcxx/test/libcxx/transitive_includes/cxx29.csv
    libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 801b11759f106..7035b01904a19 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -574,6 +574,6 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_thread_attributes``                            *unimplemented*
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_view_interface``                               *unimplemented*
+    ``__cpp_lib_view_interface``                               ``202606L``
     ========================================================== =================
 

diff  --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst
index 3cc056882eeab..a7b9e8731d555 100644
--- a/libcxx/docs/ReleaseNotes/24.rst
+++ b/libcxx/docs/ReleaseNotes/24.rst
@@ -38,6 +38,7 @@ What's New in Libc++ 24.0.0?
 Implemented Papers
 ------------------
 
+- P3052R2: ``view_interface::at()`` (`Github <https://llvm.org/PR204395>`__)
 - P0493R5: Atomic minimum/maximum (`Github <https://llvm.org/PR105418>`__)
 - P3059R2: Making user-defined constructors of view iterators/sentinels private (`Github <https://github.com/llvm/llvm-project/issues/189599>`__)
 - P0792R14: ``function_ref`` : a type-erased callable reference (`Github <https://llvm.org/PR105376>`__)

diff  --git a/libcxx/docs/Status/Cxx29Papers.csv b/libcxx/docs/Status/Cxx29Papers.csv
index 1a413c1da63f9..56fb1540e47fc 100644
--- a/libcxx/docs/Status/Cxx29Papers.csv
+++ b/libcxx/docs/Status/Cxx29Papers.csv
@@ -4,7 +4,7 @@
 "`P2414R12 <https://wg21.link/P2414R12>`__","Pointer lifetime-end zap proposed solutions","2026-06 (Brno)","","","`#204392 <https://github.com/llvm/llvm-project/issues/204392>`__","Voted as a Defect Report."
 "`P3319R6 <https://wg21.link/P3319R6>`__","Add an ``iota`` object for ``simd`` (and more)","2026-06 (Brno)","","","`#204393 <https://github.com/llvm/llvm-project/issues/204393>`__",""
 "`P3798R1 <https://wg21.link/P3798R1>`__","The unexpected in ``std::expected``","2026-06 (Brno)","|Complete|","24","`#204394 <https://github.com/llvm/llvm-project/issues/204394>`__",""
-"`P3052R2 <https://wg21.link/P3052R2>`__","``view_interface::at()``","2026-06 (Brno)","","","`#204395 <https://github.com/llvm/llvm-project/issues/204395>`__",""
+"`P3052R2 <https://wg21.link/P3052R2>`__","``view_interface::at()``","2026-06 (Brno)","24","|Complete|","`#204395 <https://github.com/llvm/llvm-project/issues/204395>`__",""
 "`P4206R0 <https://wg21.link/P4206R0>`__","Revert string support in ``std::constant_wrapper``","2026-06 (Brno)","|Complete|","23","`#203336 <https://github.com/llvm/llvm-project/issues/203336>`__","Applied as a Defect Report."
 "`P3395R6 <https://wg21.link/P3395R6>`__","Fix encoding issues and add a formatter for ``std::error_code``","2026-06 (Brno)","","","`#204396 <https://github.com/llvm/llvm-project/issues/204396>`__",""
 "`P3505R4 <https://wg21.link/P3505R4>`__","Fix the default floating-point representation in ``std::format``","2026-06 (Brno)","","","`#204397 <https://github.com/llvm/llvm-project/issues/204397>`__","To be applied as a Defect Report."

diff  --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h
index 96508c2be7277..7a2b8b27be7e7 100644
--- a/libcxx/include/__ranges/view_interface.h
+++ b/libcxx/include/__ranges/view_interface.h
@@ -15,6 +15,7 @@
 #include <__concepts/same_as.h>
 #include <__config>
 #include <__iterator/concepts.h>
+#include <__iterator/distance.h>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/prev.h>
 #include <__memory/pointer_traits.h>
@@ -25,6 +26,7 @@
 #include <__type_traits/is_class.h>
 #include <__type_traits/make_unsigned.h>
 #include <__type_traits/remove_cv.h>
+#include <stdexcept>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -159,6 +161,28 @@ class view_interface {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_
diff erence_t<_RARange> __index) const {
     return ranges::begin(__derived())[__index];
   }
+
+#  if _LIBCPP_STD_VER >= 29
+
+  template <random_access_range _RARange = _Derived>
+    requires sized_range<_RARange>
+  [[nodiscard]] constexpr decltype(auto) at(range_
diff erence_t<_RARange> __index) {
+    if (__index < 0 || __index >= ranges::distance(__derived())) {
+      std::__throw_out_of_range("The index passed to `view_interface::at()` is out of bounds.");
+    }
+    return (*this)[__index];
+  }
+
+  template <random_access_range _RARange = const _Derived>
+    requires sized_range<_RARange>
+  [[nodiscard]] constexpr decltype(auto) at(range_
diff erence_t<_RARange> __index) const {
+    if (__index < 0 || __index >= ranges::distance(__derived())) {
+      std::__throw_out_of_range("The index passed to `view_interface::at()` is out of bounds.");
+    }
+    return (*this)[__index];
+  }
+
+#  endif // _LIBCPP_STD_VER >= 29
 };
 
 } // namespace ranges

diff  --git a/libcxx/include/version b/libcxx/include/version
index 0d2f135bdcfed..c89c56fce45f5 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -674,7 +674,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 // # define __cpp_lib_simd_bitops                          202607L
 // # define __cpp_lib_simd_complex                         202502L
 // # define __cpp_lib_thread_attributes                    202606L
-// # define __cpp_lib_view_interface                       202606L
+# define __cpp_lib_view_interface                       202606L
 #endif
 
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)

diff  --git a/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
index a22c03f5d1a71..3d4c365ddfe6e 100644
--- a/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
@@ -13,6 +13,8 @@
 #include <ranges>
 #include <utility>
 
+#include "test_macros.h"
+
 struct View : std::ranges::view_interface<View> {
   int* begin();
   int* end();
@@ -67,4 +69,11 @@ void test() {
   v[Diff{0}];
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::as_const(v)[Diff{0}];
+
+#if TEST_STD_VER >= 29
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  v.at(Diff{0});
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(v).at(Diff{0});
+#endif
 }

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 44b5fe1f1577f..3c5e9439f100c 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -11,6 +11,7 @@ algorithm iosfwd
 algorithm limits
 algorithm optional
 algorithm ratio
+algorithm stdexcept
 algorithm tuple
 algorithm version
 any cstdint

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index a199c610e9f57..8c03f1c3c2251 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -11,6 +11,7 @@ algorithm iosfwd
 algorithm limits
 algorithm optional
 algorithm ratio
+algorithm stdexcept
 algorithm tuple
 algorithm version
 any cstdint

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index bd9227ca685d0..3f4daee66625a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -10,6 +10,7 @@ algorithm initializer_list
 algorithm iosfwd
 algorithm limits
 algorithm ratio
+algorithm stdexcept
 algorithm tuple
 algorithm version
 any cstdint

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx29.csv b/libcxx/test/libcxx/transitive_includes/cxx29.csv
index bd9227ca685d0..3f4daee66625a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx29.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx29.csv
@@ -10,6 +10,7 @@ algorithm initializer_list
 algorithm iosfwd
 algorithm limits
 algorithm ratio
+algorithm stdexcept
 algorithm tuple
 algorithm version
 any cstdint

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 4d6ed07bb5417..1b507cdafb33a 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
@@ -671,17 +671,11 @@
 #    error "__cpp_lib_ranges_zip should have the value 202110L in c++29"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_view_interface
-#      error "__cpp_lib_view_interface should be defined in c++29"
-#    endif
-#    if __cpp_lib_view_interface != 202606L
-#      error "__cpp_lib_view_interface should have the value 202606L in c++29"
-#    endif
-#  else
-#    ifdef __cpp_lib_view_interface
-#      error "__cpp_lib_view_interface should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_view_interface
+#    error "__cpp_lib_view_interface should be defined in c++29"
+#  endif
+#  if __cpp_lib_view_interface != 202606L
+#    error "__cpp_lib_view_interface should have the value 202606L in c++29"
 #  endif
 
 #endif // TEST_STD_VER > 26

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 a186f525cdf25..34900f78a8e92 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
@@ -10787,17 +10787,11 @@
 #    error "__cpp_lib_variant should have the value 202306L in c++29"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_view_interface
-#      error "__cpp_lib_view_interface should be defined in c++29"
-#    endif
-#    if __cpp_lib_view_interface != 202606L
-#      error "__cpp_lib_view_interface should have the value 202606L in c++29"
-#    endif
-#  else
-#    ifdef __cpp_lib_view_interface
-#      error "__cpp_lib_view_interface should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_view_interface
+#    error "__cpp_lib_view_interface should be defined in c++29"
+#  endif
+#  if __cpp_lib_view_interface != 202606L
+#    error "__cpp_lib_view_interface should have the value 202606L in c++29"
 #  endif
 
 #  ifndef __cpp_lib_void_t

diff  --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
index 196abb0f2775c..ad871207c4c71 100644
--- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
@@ -304,6 +304,50 @@ constexpr bool testSubscript() {
   return true;
 }
 
+#if TEST_STD_VER >= 29
+
+template <class T>
+concept AtInvocable = requires(T const& obj, std::size_t n) { obj.at(n); };
+
+constexpr bool testAt() {
+  static_assert(!AtInvocable<ForwardRange>);
+  static_assert(AtInvocable<RARange>);
+
+  RARange randomAccess;
+  assert(randomAccess.at(2) == 2);
+  assert(static_cast<RARange const&>(randomAccess).at(2) == 2);
+  randomAccess.at(2) = 3;
+  assert(randomAccess.at(2) == 3);
+
+#  ifndef TEST_HAS_NO_EXCEPTIONS
+  if (!std::is_constant_evaluated()) {
+    try {
+      TEST_IGNORE_NODISCARD randomAccess.at(0);
+      assert(true);
+    } catch (std::out_of_range const&) {
+      // pass
+      assert(false); // This should not be reached because index 0 is valid.
+    } catch (...) {
+      assert(false);
+    }
+
+    // Test that at() throws an exception when the index is out of range.
+    try {
+      TEST_IGNORE_NODISCARD randomAccess.at(10);
+      assert(false);
+    } catch (std::out_of_range const&) {
+      // pass
+    } catch (...) {
+      assert(false);
+    }
+  }
+#  endif
+
+  return true;
+}
+
+#endif // TEST_STD_VER >= 29
+
 template <class T>
 concept FrontInvocable = requires(T const& obj) { obj.front(); };
 
@@ -355,6 +399,11 @@ int main(int, char**) {
   testSubscript();
   static_assert(testSubscript());
 
+#if TEST_STD_VER >= 29
+  testAt();
+  static_assert(testAt());
+#endif
+
   testFrontBack();
   static_assert(testFrontBack());
 

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 7139a62f605d9..8cc54971c57c9 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1612,7 +1612,6 @@ def add_version_header(tc):
                 "c++29": 202606,  # P3052R2 view_interface::at()
             },
             "headers": ["ranges"],
-            "unimplemented": True,
         },
         {
             "name": "__cpp_lib_void_t",


        


More information about the libcxx-commits mailing list