[libcxx-commits] [libcxx] [libc++][ranges][enumerate_view] Fix sentinel converting constructor test (PR #217365)
Lucas Mellone via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Aug 20 01:57:57 PDT 2026
https://github.com/lknknm updated https://github.com/llvm/llvm-project/pull/217365
>From a5d6d8feb899d759277c82e318b10d2585b3ae55 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Tue, 18 Aug 2026 16:07:44 +0200
Subject: [PATCH 1/7] add: sentinel wrapper and
NonSimpleNonCommonConvertibleView
---
.../sentinel/ctor.convert.pass.cpp | 54 ++++++++++++++-----
1 file changed, 42 insertions(+), 12 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
index b3bee42685a9a..f03f1c60b849f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -29,6 +29,32 @@
#include "../types.h"
+template <class T>
+struct convertible_sentinel_wrapper {
+ explicit convertible_sentinel_wrapper() = default;
+ contexpr convertible_sentinel_wrapper(const T& it) : it_(it) {}
+
+ template <class U>
+ requires std::convertible_to<const U&, T>
+ constexpr convertible_sentinel_wrapper(const convertible_sentinel_wrapper<U>& other) : it_(other.it_) {}
+
+ constexpr friend bool operator==(convertible_sentinel_wrapper const& self, const T& other) {
+ return self.it_ == other;
+ }
+ T it_;
+};
+
+struct NonSimpleNonCommonConvertibleView : IntBufferView {
+ using IntBufferView::IntBufferView;
+
+ constexpr int* begin() { return buffer_; }
+ constexpr const int* begin() const { return buffer_; }
+ constexpr convertible_sentinel_wrapper<int*> end() { return convertible_sentinel_wrapper<int*>(buffer_ + size_; }
+ constexpr convertible_sentinel_wrapper<const int*> end() const {
+ return convertible_sentinel_wrapper<const int*>(buffer_ + size_);
+ }
+};
+
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
constexpr void test() {
using View = MinimalView<Iterator, Sentinel>;
@@ -46,18 +72,22 @@ constexpr void test() {
std::array array{0, 1, 2, 3, 84};
auto view = make_enumerate_view(array.begin(), array.end());
-
- std::same_as<EnumerateSentinel> decltype(auto) s = view.end();
- std::same_as<Sentinel> decltype(auto) sResult = s.base();
- assert(base(base(sResult)) == std::to_address(base(array.end())));
-
- // Test assignment
- EnumerateConstSentinel cs = s;
- std::same_as<Sentinel> decltype(auto) csResult = cs.base();
- assert(base(base(csResult)) == std::to_address(base(array.end())));
+
+ {
+ // Assigning a non-const sentinel to a const-sentinel-typed variable invokes
+ // the converting constructor.
+ std::same_as<EnumerateSentinel> decltype(auto) s = view.end();
+ std::same_as<Sentinel> decltype(auto) sResult = s.base();
+ assert(base(base(sResult)) == std::to_address(base(array.end())));
+
+ // Verify assignment
+ EnumerateConstSentinel cs = s;
+ std::same_as<Sentinel> decltype(auto) csResult = cs.base();
+ assert(base(base(csResult)) == std::to_address(base(array.end())));
+ }
}
-constexpr bool tests() {
+constexpr bool test() {
test<cpp17_input_iterator<int*>>();
test<cpp20_input_iterator<int*>>();
test<forward_iterator<int*>>();
@@ -70,8 +100,8 @@ constexpr bool tests() {
}
int main(int, char**) {
- tests();
- static_assert(tests());
+ test();
+ static_assert(test());
return 0;
}
>From 69d0bd155ceaf64e12fcef7565e5a0f810d35b09 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Wed, 19 Aug 2026 01:00:00 +0200
Subject: [PATCH 2/7] wip: add Underlying non-const to const not convertible
test case
---
.../sentinel/ctor.convert.pass.cpp | 60 +++++++++++++------
1 file changed, 42 insertions(+), 18 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
index f03f1c60b849f..a5d255f75bb29 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -28,33 +28,55 @@
#include "test_iterators.h"
#include "../types.h"
+#include "../../range_adaptor_types.h"
template <class T>
struct convertible_sentinel_wrapper {
- explicit convertible_sentinel_wrapper() = default;
- contexpr convertible_sentinel_wrapper(const T& it) : it_(it) {}
+ explicit convertible_sentinel_wrapper() = default;
+ constexpr convertible_sentinel_wrapper(const T& it) : it_(it) {}
- template <class U>
- requires std::convertible_to<const U&, T>
- constexpr convertible_sentinel_wrapper(const convertible_sentinel_wrapper<U>& other) : it_(other.it_) {}
+ template <class U>
+ requires std::convertible_to<const U&, T>
+ constexpr convertible_sentinel_wrapper(const convertible_sentinel_wrapper<U>& other) : it_(other.it_) {}
- constexpr friend bool operator==(convertible_sentinel_wrapper const& self, const T& other) {
- return self.it_ == other;
- }
- T it_;
+ constexpr friend bool operator==(convertible_sentinel_wrapper const& self, const T& other) {
+ return self.it_ == other;
+ }
+ T it_;
};
struct NonSimpleNonCommonConvertibleView : IntBufferView {
- using IntBufferView::IntBufferView;
-
- constexpr int* begin() { return buffer_; }
- constexpr const int* begin() const { return buffer_; }
- constexpr convertible_sentinel_wrapper<int*> end() { return convertible_sentinel_wrapper<int*>(buffer_ + size_; }
- constexpr convertible_sentinel_wrapper<const int*> end() const {
- return convertible_sentinel_wrapper<const int*>(buffer_ + size_);
- }
+ using IntBufferView::IntBufferView;
+
+ constexpr int* begin() { return buffer_; }
+ constexpr const int* begin() const { return buffer_; }
+ constexpr convertible_sentinel_wrapper<int*> end() { return convertible_sentinel_wrapper<int*>(buffer_ + size_); }
+ constexpr convertible_sentinel_wrapper<const int*> end() const {
+ return convertible_sentinel_wrapper<const int*>(buffer_ + size_);
+ }
};
+// convertible_to<sentinel<false>, sentinel<Const>>
+static_assert(std::convertible_to< //
+ std::ranges::sentinel_t<std::ranges::enumerate_view<NonSimpleNonCommonConvertibleView>>,
+ std::ranges::sentinel_t<std::ranges::enumerate_view<NonSimpleNonCommonConvertibleView> const>>);
+
+constexpr void test_SFINAE() {
+ int buffer[3] = {1, 2, 3};
+
+ // Underlying non-const to const not convertible.
+ {
+ std::ranges::enumerate_view v{NonSimpleNonCommonConvertibleView(buffer)};
+ auto sent1 = v.end();
+ auto sent2 = std::as_const(v).end();
+
+ static_assert(!std::same_as<decltype(sent1), decltype(sent2)>);
+
+ static_assert(!std::is_constructible_v<decltype(sent1), decltype(sent2)>);
+ static_assert(!std::is_constructible_v<decltype(sent2), decltype(sent1)>); // this assert fails
+ }
+}
+
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
constexpr void test() {
using View = MinimalView<Iterator, Sentinel>;
@@ -72,7 +94,7 @@ constexpr void test() {
std::array array{0, 1, 2, 3, 84};
auto view = make_enumerate_view(array.begin(), array.end());
-
+
{
// Assigning a non-const sentinel to a const-sentinel-typed variable invokes
// the converting constructor.
@@ -88,6 +110,8 @@ constexpr void test() {
}
constexpr bool test() {
+ test_SFINAE();
+
test<cpp17_input_iterator<int*>>();
test<cpp20_input_iterator<int*>>();
test<forward_iterator<int*>>();
>From 8f3af3e95e1981d5750ed1c7a3a82cd9ebd21739 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Wed, 19 Aug 2026 16:26:51 +0200
Subject: [PATCH 3/7] add: test case for const st to non-const st
---
.../range.enumerate/sentinel/ctor.convert.pass.cpp | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
index a5d255f75bb29..43da253f34934 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -75,6 +75,16 @@ constexpr void test_SFINAE() {
static_assert(!std::is_constructible_v<decltype(sent1), decltype(sent2)>);
static_assert(!std::is_constructible_v<decltype(sent2), decltype(sent1)>); // this assert fails
}
+ {
+ std::ranges::enumerate_view v{NonSimpleNonCommonConvertibleView(buffer)};
+ auto sent1 = v.end();
+ std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+
+ static_assert(!std::same_as<decltype(sent1), decltype(sent2)>);
+
+ // We cannot create a non-const sentinel from a const sentinel.
+ static_assert(!std::is_constructible_v<decltype(sent1), decltype(sent2)>);
+ }
}
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
>From 71696d1d1278f03384c9297a70c60e7278c47c11 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Wed, 19 Aug 2026 17:25:50 +0200
Subject: [PATCH 4/7] fix assertions
---
.../range.enumerate/sentinel/ctor.convert.pass.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
index 43da253f34934..e376b64cc979d 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -72,8 +72,11 @@ constexpr void test_SFINAE() {
static_assert(!std::same_as<decltype(sent1), decltype(sent2)>);
+ // We cannot create a non-const sentinel from a const sentinel.
static_assert(!std::is_constructible_v<decltype(sent1), decltype(sent2)>);
- static_assert(!std::is_constructible_v<decltype(sent2), decltype(sent1)>); // this assert fails
+
+ // We can create a const sentinel from a non-const sentinel.
+ static_assert(std::is_constructible_v<decltype(sent2), decltype(sent1)>);
}
{
std::ranges::enumerate_view v{NonSimpleNonCommonConvertibleView(buffer)};
>From 2bf68e00a8609a3417ca1edbe4a573c4c45c69c0 Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Wed, 19 Aug 2026 17:35:44 +0200
Subject: [PATCH 5/7] fix: clang-format
---
.../range.enumerate/sentinel/ctor.convert.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
index e376b64cc979d..ee5934a9da07a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -80,7 +80,7 @@ constexpr void test_SFINAE() {
}
{
std::ranges::enumerate_view v{NonSimpleNonCommonConvertibleView(buffer)};
- auto sent1 = v.end();
+ auto sent1 = v.end();
std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
static_assert(!std::same_as<decltype(sent1), decltype(sent2)>);
>From 473a0d03bc379c36218053614dfe4658a52f124b Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Thu, 20 Aug 2026 10:54:02 +0200
Subject: [PATCH 6/7] Apply suggestions from code review
Co-authored-by: Hristo Hristov <zingam at outlook.com>
---
.../range.enumerate/sentinel/ctor.convert.pass.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
index ee5934a9da07a..37b1df1734f4a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -27,8 +27,8 @@
#include "test_iterators.h"
-#include "../types.h"
#include "../../range_adaptor_types.h"
+#include "../types.h"
template <class T>
struct convertible_sentinel_wrapper {
@@ -57,7 +57,7 @@ struct NonSimpleNonCommonConvertibleView : IntBufferView {
};
// convertible_to<sentinel<false>, sentinel<Const>>
-static_assert(std::convertible_to< //
+static_assert(std::convertible_to<
std::ranges::sentinel_t<std::ranges::enumerate_view<NonSimpleNonCommonConvertibleView>>,
std::ranges::sentinel_t<std::ranges::enumerate_view<NonSimpleNonCommonConvertibleView> const>>);
@@ -67,8 +67,8 @@ constexpr void test_SFINAE() {
// Underlying non-const to const not convertible.
{
std::ranges::enumerate_view v{NonSimpleNonCommonConvertibleView(buffer)};
- auto sent1 = v.end();
- auto sent2 = std::as_const(v).end();
+ auto st= v.end();
+ auto const_st= std::as_const(v).end();
static_assert(!std::same_as<decltype(sent1), decltype(sent2)>);
@@ -111,7 +111,7 @@ constexpr void test() {
{
// Assigning a non-const sentinel to a const-sentinel-typed variable invokes
// the converting constructor.
- std::same_as<EnumerateSentinel> decltype(auto) s = view.end();
+ std::same_as<EnumerateSentinel> decltype(auto) st = view.end();
std::same_as<Sentinel> decltype(auto) sResult = s.base();
assert(base(base(sResult)) == std::to_address(base(array.end())));
>From 28f8ba8e1364db1a0e0971ff312eb247519761cc Mon Sep 17 00:00:00 2001
From: Lucas Mellone <github.snugness349 at passinbox.com>
Date: Thu, 20 Aug 2026 10:57:42 +0200
Subject: [PATCH 7/7] fix: few variable and clang-format fixes from code review
---
.../sentinel/ctor.convert.pass.cpp | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
index 37b1df1734f4a..ce382dcdc8eb4 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/sentinel/ctor.convert.pass.cpp
@@ -67,26 +67,26 @@ constexpr void test_SFINAE() {
// Underlying non-const to const not convertible.
{
std::ranges::enumerate_view v{NonSimpleNonCommonConvertibleView(buffer)};
- auto st= v.end();
- auto const_st= std::as_const(v).end();
+ auto st = v.end();
+ auto const_st = std::as_const(v).end();
- static_assert(!std::same_as<decltype(sent1), decltype(sent2)>);
+ static_assert(!std::same_as<decltype(st), decltype(const_st)>);
// We cannot create a non-const sentinel from a const sentinel.
- static_assert(!std::is_constructible_v<decltype(sent1), decltype(sent2)>);
+ static_assert(!std::is_constructible_v<decltype(st), decltype(const_st)>);
// We can create a const sentinel from a non-const sentinel.
- static_assert(std::is_constructible_v<decltype(sent2), decltype(sent1)>);
+ static_assert(std::is_constructible_v<decltype(const_st), decltype(st)>);
}
{
std::ranges::enumerate_view v{NonSimpleNonCommonConvertibleView(buffer)};
- auto sent1 = v.end();
- std::ranges::sentinel_t<const decltype(v)> sent2 = sent1;
+ auto st = v.end();
+ std::ranges::sentinel_t<const decltype(v)> const_st = st;
- static_assert(!std::same_as<decltype(sent1), decltype(sent2)>);
+ static_assert(!std::same_as<decltype(st), decltype(const_st)>);
// We cannot create a non-const sentinel from a const sentinel.
- static_assert(!std::is_constructible_v<decltype(sent1), decltype(sent2)>);
+ static_assert(!std::is_constructible_v<decltype(st), decltype(const_st)>);
}
}
@@ -112,11 +112,11 @@ constexpr void test() {
// Assigning a non-const sentinel to a const-sentinel-typed variable invokes
// the converting constructor.
std::same_as<EnumerateSentinel> decltype(auto) st = view.end();
- std::same_as<Sentinel> decltype(auto) sResult = s.base();
+ std::same_as<Sentinel> decltype(auto) sResult = st.base();
assert(base(base(sResult)) == std::to_address(base(array.end())));
// Verify assignment
- EnumerateConstSentinel cs = s;
+ EnumerateConstSentinel cs = st;
std::same_as<Sentinel> decltype(auto) csResult = cs.base();
assert(base(base(csResult)) == std::to_address(base(array.end())));
}
More information about the libcxx-commits
mailing list