[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