[libcxx-commits] [libcxx] 12f2c46 - [libc++][ranges] Implement LWG3797: `elements_view` insufficiently constrained (#236930)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Oct 31 09:28:50 PDT 2026
Author: R. Aoto
Date: 2026-11-01T00:28:45+08:00
New Revision: 12f2c4657237fa416e685512fc9d586280ec4397
URL: https://github.com/llvm/llvm-project/commit/12f2c4657237fa416e685512fc9d586280ec4397
DIFF: https://github.com/llvm/llvm-project/commit/12f2c4657237fa416e685512fc9d586280ec4397.diff
LOG: [libc++][ranges] Implement LWG3797: `elements_view` insufficiently constrained (#236930)
Require `std::get<N>(t)` to be valid in `has-tuple-element`. Previously,
a range of `subrange`s over a move-only iterator satisfied the
constraints of `elements_view<V, 0>` and then failed with a hard error,
because `subrange`'s lvalue `get<0>` requires `copyable<I>`.
Fixes #189811
Added:
Modified:
libcxx/docs/Status/Cxx26Issues.csv
libcxx/include/__ranges/elements_view.h
libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/Status/Cxx26Issues.csv b/libcxx/docs/Status/Cxx26Issues.csv
index 638f7a4e6ffa15..bb6f584898263b 100644
--- a/libcxx/docs/Status/Cxx26Issues.csv
+++ b/libcxx/docs/Status/Cxx26Issues.csv
@@ -266,7 +266,7 @@
"`LWG3599 <https://wg21.link/LWG3599>`__","The ``const`` overload of ``lazy_split_view::begin`` should be constrained by ``const Pattern``","2026-03 (Croydon)","|Complete|","24","`#189808 <https://github.com/llvm/llvm-project/issues/189808>`__",""
"`LWG3662 <https://wg21.link/LWG3662>`__","``basic_string::append/assign(NTBS, pos, n)`` suboptimal","2026-03 (Croydon)","|Complete|","23","`#189809 <https://github.com/llvm/llvm-project/issues/189809>`__",""
"`LWG3777 <https://wg21.link/LWG3777>`__","Common ``cartesian_product_view`` produces an invalid range if the first range is input and one of the ranges is empty","2026-03 (Croydon)","","","`#189810 <https://github.com/llvm/llvm-project/issues/189810>`__",""
-"`LWG3797 <https://wg21.link/LWG3797>`__","``elements_view`` insufficiently constrained","2026-03 (Croydon)","","","`#189811 <https://github.com/llvm/llvm-project/issues/189811>`__",""
+"`LWG3797 <https://wg21.link/LWG3797>`__","``elements_view`` insufficiently constrained","2026-03 (Croydon)","|Complete|","24","`#189811 <https://github.com/llvm/llvm-project/issues/189811>`__",""
"`LWG3831 <https://wg21.link/LWG3831>`__","Two-digit formatting of negative ``year`` is ambiguous","2026-03 (Croydon)","","","`#189812 <https://github.com/llvm/llvm-project/issues/189812>`__",""
"`LWG3891 <https://wg21.link/LWG3891>`__","LWG3870 breaks ``std::expected<cv T, E>``","2026-03 (Croydon)","","","`#189813 <https://github.com/llvm/llvm-project/issues/189813>`__",""
"`LWG4026 <https://wg21.link/LWG4026>`__","Assignment operators of ``std::expected`` should propagate triviality","2026-03 (Croydon)","","","`#189814 <https://github.com/llvm/llvm-project/issues/189814>`__",""
diff --git a/libcxx/include/__ranges/elements_view.h b/libcxx/include/__ranges/elements_view.h
index 3b7c2f34426978..3678e15719a8af 100644
--- a/libcxx/include/__ranges/elements_view.h
+++ b/libcxx/include/__ranges/elements_view.h
@@ -53,7 +53,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
template <class _Tp, size_t _Np>
-concept __has_tuple_element = __tuple_like<_Tp> && _Np < tuple_size<_Tp>::value;
+concept __has_tuple_element = __tuple_like<_Tp> && _Np < tuple_size<_Tp>::value && requires(_Tp __t) {
+ { std::get<_Np>(__t) } -> convertible_to<const tuple_element_t<_Np, _Tp>&>;
+};
template <class _Tp, size_t _Np>
concept __returnable_element = is_reference_v<_Tp> || move_constructible<tuple_element_t<_Np, _Tp>>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp
index a49e692d585da6..7aca3e49d720bf 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.elements/range.concept.compile.pass.cpp
@@ -12,7 +12,10 @@
//
// template<class T, size_t N>
// concept has-tuple-element =
-// tuple-like<T> && N < tuple_size_v<T>;
+// tuple-like<T> && N < tuple_size_v<T> &&
+// requires(T t) {
+// { std::get<N>(t) } -> convertible_to<const tuple_element_t<N, T>&>;
+// };
//
// template<class T, size_t N>
// concept returnable-element =
@@ -72,3 +75,11 @@ using NonMovableGenerator =
static_assert(!HasElementsView<NonMovableGenerator, 0>);
static_assert(HasElementsView<NonMovableGenerator, 1>);
+
+// LWG3797: subrange's get<0> requires copyable<I>, so std::get<0>(t) is invalid for a move-only iterator.
+using MoveOnlySubrange = Range<cpp20_input_iterator<int*>>;
+
+static_assert(!std::copyable<cpp20_input_iterator<int*>>);
+static_assert(!HasElementsView<Range<MoveOnlySubrange*>, 0>);
+static_assert(HasElementsView<Range<MoveOnlySubrange*>, 1>);
+static_assert(!HasElementsView<Range<const MoveOnlySubrange*>, 0>);
More information about the libcxx-commits
mailing list