[libcxx-commits] [libcxx] [libc++] LWG4012: common_view::begin/end are missing the simple-view check (PR #153674)

Nhat Nguyen via libcxx-commits libcxx-commits at lists.llvm.org
Mon Aug 18 12:55:07 PDT 2025


https://github.com/changkhothuychung updated https://github.com/llvm/llvm-project/pull/153674

>From 06a6c6168ca510ed773346f57693a2b273451208 Mon Sep 17 00:00:00 2001
From: changkhothuychung <nhat7203 at gmail.com>
Date: Thu, 14 Aug 2025 16:35:58 -0400
Subject: [PATCH 1/3] initial commit

---
 libcxx/include/__ranges/common_view.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/common_view.h b/libcxx/include/__ranges/common_view.h
index 133236dd1d78a..ff26a78c00052 100644
--- a/libcxx/include/__ranges/common_view.h
+++ b/libcxx/include/__ranges/common_view.h
@@ -58,7 +58,7 @@ class common_view : public view_interface<common_view<_View>> {
 
   _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto begin() {
+  _LIBCPP_HIDE_FROM_ABI constexpr auto begin() requires (!__simple_view<_View>) {
     if constexpr (random_access_range<_View> && sized_range<_View>)
       return ranges::begin(__base_);
     else
@@ -74,7 +74,7 @@ class common_view : public view_interface<common_view<_View>> {
       return common_iterator<iterator_t<const _View>, sentinel_t<const _View>>(ranges::begin(__base_));
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto end() {
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end() requires (!__simple_view<_View>) {
     if constexpr (random_access_range<_View> && sized_range<_View>)
       return ranges::begin(__base_) + ranges::size(__base_);
     else

>From 31d0cefaf9ffe931a58d7cabd4afbb1fe7e287bf Mon Sep 17 00:00:00 2001
From: changkhothuychung <nhat7203 at gmail.com>
Date: Thu, 14 Aug 2025 16:43:57 -0400
Subject: [PATCH 2/3] clang format

---
 libcxx/include/__ranges/common_view.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/common_view.h b/libcxx/include/__ranges/common_view.h
index ff26a78c00052..54bb8039b48af 100644
--- a/libcxx/include/__ranges/common_view.h
+++ b/libcxx/include/__ranges/common_view.h
@@ -58,7 +58,9 @@ class common_view : public view_interface<common_view<_View>> {
 
   _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto begin() requires (!__simple_view<_View>) {
+  _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+    requires(!__simple_view<_View>)
+  {
     if constexpr (random_access_range<_View> && sized_range<_View>)
       return ranges::begin(__base_);
     else
@@ -74,7 +76,9 @@ class common_view : public view_interface<common_view<_View>> {
       return common_iterator<iterator_t<const _View>, sentinel_t<const _View>>(ranges::begin(__base_));
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto end() requires (!__simple_view<_View>) {
+  _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+    requires(!__simple_view<_View>)
+  {
     if constexpr (random_access_range<_View> && sized_range<_View>)
       return ranges::begin(__base_) + ranges::size(__base_);
     else

>From 265621cf45d58a768b83130da2fd2c071a5f21c3 Mon Sep 17 00:00:00 2001
From: changkhothuychung <nhat7203 at gmail.com>
Date: Mon, 18 Aug 2025 15:54:31 -0400
Subject: [PATCH 3/3] sfinae test

---
 .../range.common.view/begin.pass.cpp          | 31 ++++++++++++++++---
 .../range.common.view/end.pass.cpp            |  7 +++++
 .../range.adaptors/range.common.view/types.h  | 13 ++++++++
 3 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp
index 96116dc37553a..ab74e1efb930f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp
@@ -25,16 +25,30 @@ struct MutableView : std::ranges::view_base {
   sentinel_wrapper<int*> end();
 };
 
-template<class View>
-concept BeginEnabled = requires(View v) { v.begin(); };
+template <class T>
+concept HasConstBegin = requires(const T& ct) { ct.begin(); };
+
+template <class T>
+concept HasBegin = requires(T& t) { t.begin(); };
+
+template <class T>
+concept HasConstAndNonConstBegin = HasConstBegin<T> && requires(T& t, const T& ct) {
+  requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>;
+};
+
+template <class T>
+concept HasOnlyNonConstBegin = HasBegin<T> && !HasConstBegin<T>;
+
+template <class T>
+concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
 
 constexpr bool test() {
   int buf[8] = {1, 2, 3, 4, 5, 6, 7, 8};
 
   {
-    static_assert( BeginEnabled<std::ranges::common_view<CopyableView> const&>);
-    static_assert( BeginEnabled<std::ranges::common_view<MutableView>&>);
-    static_assert(!BeginEnabled<std::ranges::common_view<MutableView> const&>);
+    static_assert( HasBegin<std::ranges::common_view<CopyableView> const&>);
+    static_assert( HasBegin<std::ranges::common_view<MutableView>&>);
+    static_assert(!HasBegin<std::ranges::common_view<MutableView> const&>);
   }
 
   {
@@ -51,6 +65,13 @@ constexpr bool test() {
     assert(begin == std::ranges::begin(view));
   }
 
+  {
+    NonSimpleNonCommonView view{buf, buf + 8};
+    std::ranges::common_view<NonSimpleNonCommonView> common(view);
+    static_assert(!std::ranges::__simple_view<NonSimpleNonCommonView>);
+    static_assert(!std::is_same_v<decltype(common.begin()), decltype(std::as_const(common).begin())>);
+  }
+
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp
index 0565ed02f2716..8feb028e93893 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp
@@ -39,6 +39,13 @@ constexpr bool test() {
     assert(base(end) == buf + 8);
   }
 
+  {
+    NonSimpleNonCommonView view{buf, buf + 8};
+    std::ranges::common_view<NonSimpleNonCommonView> common(view);
+    static_assert(!std::ranges::__simple_view<NonSimpleNonCommonView>);
+    static_assert(!std::is_same_v<decltype(common.end()), decltype(std::as_const(common).end())>);
+  }
+
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
index 18354483fd329..dca4b7a33d348 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
@@ -90,4 +90,17 @@ struct NonCommonView : std::ranges::view_base {
 static_assert( std::ranges::view<NonCommonView>);
 static_assert(!std::ranges::common_range<NonCommonView>);
 
+
+template<bool Simple>
+struct NonCommonBaseView: std::ranges::view_base {
+  int* begin_;
+  int* end_;
+  constexpr explicit NonCommonBaseView(int* b, int* e) : begin_(b), end_(e) { }
+  constexpr auto begin() const { return static_cast<const int*>(begin_); }
+  constexpr auto end() const { return sentinel_wrapper<const int*>(end_); }
+  constexpr int *begin() requires (!Simple) { return begin_; }
+  constexpr auto end() requires (!Simple) { return sentinel_wrapper<int*>(end_); }
+};
+using NonSimpleNonCommonView = NonCommonBaseView<false>;
+
 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_COMMON_VIEW_TYPES_H



More information about the libcxx-commits mailing list