[libcxx-commits] [libcxx] [libc++][ranges] LWG4096: `views::iota(views::iota(0))` should be rejected (PR #152855)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Aug 11 10:53:36 PDT 2025
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/152855
>From e66aca58e43cfb9fcb55bc4025b12e6b57031f72 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 9 Aug 2025 11:45:35 +0300
Subject: [PATCH 1/5] [libc++][ranges] LWG4096: `views::iota(views::iota(0))`
should be rejected
Fixes: #105352
---
libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
libcxx/include/__ranges/iota_view.h | 3 +-
.../range.iota.view/views_iota.verify.cpp | 29 +++++++++++++++++++
3 files changed, 32 insertions(+), 2 deletions(-)
create mode 100644 libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 6fcb2f3c78cfc..9b61c921c8db4 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -71,7 +71,7 @@
"`LWG4079 <https://wg21.link/LWG4079>`__","Missing Preconditions in ``concat_view::iterator``\`s conversion constructor","2024-06 (St. Louis)","","",""
"`LWG4082 <https://wg21.link/LWG4082>`__","``views::concat(r)`` is well-formed when ``r`` is an ``output_range``","2024-06 (St. Louis)","","",""
"`LWG4083 <https://wg21.link/LWG4083>`__","``views::as_rvalue`` should reject non-input ranges","2024-06 (St. Louis)","","",""
-"`LWG4096 <https://wg21.link/LWG4096>`__","``views::iota(views::iota(0))`` should be rejected","2024-06 (St. Louis)","","",""
+"`LWG4096 <https://wg21.link/LWG4096>`__","``views::iota(views::iota(0))`` should be rejected","2024-06 (St. Louis)","|Complete|","22",""
"`LWG4098 <https://wg21.link/LWG4098>`__","``views::adjacent<0>`` should reject non-forward ranges","2024-06 (St. Louis)","","",""
"`LWG4105 <https://wg21.link/LWG4105>`__","``ranges::ends_with``\`s Returns misses difference casting","2024-06 (St. Louis)","","",""
"`LWG4106 <https://wg21.link/LWG4106>`__","``basic_format_args`` should not be default-constructible","2024-06 (St. Louis)","|Complete|","19",""
diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h
index 4b84585258b91..79a450a9ce40c 100644
--- a/libcxx/include/__ranges/iota_view.h
+++ b/libcxx/include/__ranges/iota_view.h
@@ -30,6 +30,7 @@
#include <__ranges/movable_box.h>
#include <__ranges/view_interface.h>
#include <__type_traits/conditional.h>
+#include <__type_traits/decay.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/make_unsigned.h>
#include <__type_traits/type_identity.h>
@@ -377,7 +378,7 @@ struct __fn {
_LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Start&& __start) const
noexcept(noexcept(ranges::iota_view(std::forward<_Start>(__start))))
-> decltype(ranges::iota_view(std::forward<_Start>(__start))) {
- return ranges::iota_view(std::forward<_Start>(__start));
+ return ranges::iota_view<decay_t<_Start>>(std::forward<_Start>(__start));
}
template <class _Start, class _BoundSentinel>
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
new file mode 100644
index 0000000000000..9f1879968eebc
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+// views::iota
+
+#include <ranges>
+
+#include "types.h"
+
+void test() {
+ // LWG4096
+ {
+ [[maybe_unused]] auto i1 = std::views::iota(0); // OK
+ [[maybe_unused]] auto i2 = std::views::iota(std::views::iota(0));
+ // expected-error-re@*:* {{constraints not satisfied for class template 'iota_view'{{.*}}}}
+ }
+ {
+ [[maybe_unused]] auto i1 = std::views::iota(SomeInt(0)); // OK
+ [[maybe_unused]] auto i2 = std::views::iota(std::views::iota(SomeInt(0)));
+ //expected-error-re@*:* {{constraints not satisfied for class template 'iota_view'{{.*}}}}
+ }
+}
>From 7b50536a1f14c351c2d63b17215322fc0b45e8ee Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 9 Aug 2025 17:39:14 +0300
Subject: [PATCH 2/5] Constrained CPO
---
libcxx/include/__ranges/iota_view.h | 1 +
.../range.iota.view/views_iota.pass.cpp | 19 ++++++++++++++++++-
.../range.iota.view/views_iota.verify.cpp | 4 ++--
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h
index 79a450a9ce40c..7db803effaff0 100644
--- a/libcxx/include/__ranges/iota_view.h
+++ b/libcxx/include/__ranges/iota_view.h
@@ -375,6 +375,7 @@ namespace views {
namespace __iota {
struct __fn {
template <class _Start>
+ requires(requires(_Start __s) { ranges::iota_view<decay_t<_Start>>(std::forward<_Start>(__s)); })
_LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Start&& __start) const
noexcept(noexcept(ranges::iota_view(std::forward<_Start>(__start))))
-> decltype(ranges::iota_view(std::forward<_Start>(__start))) {
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
index a6b268fd6a8d8..c28523d4b753f 100644
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
@@ -46,7 +46,14 @@ constexpr void testType(U u) {
struct X {};
-constexpr bool test() {
+template <typename IntT>
+concept CanDoubleWrap = requires(IntT i) { std::views::iota(std::views::iota(i)); };
+
+template <typename T>
+concept HasIota = requires(T t) { std::views::iota(t); };
+
+constexpr bool
+test() {
testType<SomeInt>(SomeInt(10));
testType<SomeInt>(IntComparableWith(SomeInt(10)));
testType<signed long>(IntComparableWith<signed long>(10));
@@ -68,6 +75,16 @@ constexpr bool test() {
{
static_assert(std::same_as<decltype(std::views::iota), decltype(std::ranges::views::iota)>);
}
+ { // LWG4096
+ // [[maybe_unused]] auto i1 = std::views::iota(std::views::iota(82));
+ // [[maybe_unused]] auto i2 = std::views::iota(std::views::iota(SomeInt(94)));
+
+ static_assert(!CanDoubleWrap<int>);
+ static_assert(!CanDoubleWrap<SomeInt>);
+ static_assert(!HasIota<decltype(std::views::iota(82))>);
+ static_assert(!HasIota<decltype(std::views::iota(SomeInt(94)))>);
+ static_assert(!std::is_invocable_v<decltype(std::views::iota), decltype(std::views::iota(82))>);
+ }
return true;
}
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
index 9f1879968eebc..7f644c54ab8d6 100644
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
@@ -19,11 +19,11 @@ void test() {
{
[[maybe_unused]] auto i1 = std::views::iota(0); // OK
[[maybe_unused]] auto i2 = std::views::iota(std::views::iota(0));
- // expected-error-re@*:* {{constraints not satisfied for class template 'iota_view'{{.*}}}}
+ // expected-error@*:* {{no matching function for call to object of type 'const __iota::__fn'}}
}
{
[[maybe_unused]] auto i1 = std::views::iota(SomeInt(0)); // OK
[[maybe_unused]] auto i2 = std::views::iota(std::views::iota(SomeInt(0)));
- //expected-error-re@*:* {{constraints not satisfied for class template 'iota_view'{{.*}}}}
+ //expected-error@*:* {{no matching function for call to object of type 'const __iota::__fn'}}
}
}
>From 28a1cde3b8090ad91e5bd89954eb208ee0b94beb Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 9 Aug 2025 17:41:42 +0300
Subject: [PATCH 3/5] Cleanup
---
.../range.iota.view/views_iota.pass.cpp | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
index c28523d4b753f..a2e883f20b9a1 100644
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
@@ -49,9 +49,6 @@ struct X {};
template <typename IntT>
concept CanDoubleWrap = requires(IntT i) { std::views::iota(std::views::iota(i)); };
-template <typename T>
-concept HasIota = requires(T t) { std::views::iota(t); };
-
constexpr bool
test() {
testType<SomeInt>(SomeInt(10));
@@ -75,14 +72,10 @@ test() {
{
static_assert(std::same_as<decltype(std::views::iota), decltype(std::ranges::views::iota)>);
}
- { // LWG4096
- // [[maybe_unused]] auto i1 = std::views::iota(std::views::iota(82));
- // [[maybe_unused]] auto i2 = std::views::iota(std::views::iota(SomeInt(94)));
-
+ { // LWG4096: views::iota(views::iota(0)) should be rejected
static_assert(!CanDoubleWrap<int>);
static_assert(!CanDoubleWrap<SomeInt>);
- static_assert(!HasIota<decltype(std::views::iota(82))>);
- static_assert(!HasIota<decltype(std::views::iota(SomeInt(94)))>);
+
static_assert(!std::is_invocable_v<decltype(std::views::iota), decltype(std::views::iota(82))>);
}
>From 0d3d14a287542fbe0733ba6c565fcd5517ff7682 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 9 Aug 2025 17:57:06 +0300
Subject: [PATCH 4/5] Fixed formatting
---
.../ranges/range.factories/range.iota.view/views_iota.pass.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
index a2e883f20b9a1..cdc873b7c818f 100644
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
@@ -49,8 +49,7 @@ struct X {};
template <typename IntT>
concept CanDoubleWrap = requires(IntT i) { std::views::iota(std::views::iota(i)); };
-constexpr bool
-test() {
+constexpr bool test() {
testType<SomeInt>(SomeInt(10));
testType<SomeInt>(IntComparableWith(SomeInt(10)));
testType<signed long>(IntComparableWith<signed long>(10));
>From a24a256a7079e7d37fd6add00909a6cdcaf6eade Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hristo.goshev.hristov at gmail.com>
Date: Mon, 11 Aug 2025 20:52:31 +0300
Subject: [PATCH 5/5] Delete
libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
---
.../range.iota.view/views_iota.verify.cpp | 29 -------------------
1 file changed, 29 deletions(-)
delete mode 100644 libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
deleted file mode 100644
index 7f644c54ab8d6..0000000000000
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.verify.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: std-at-least-c++20
-
-// views::iota
-
-#include <ranges>
-
-#include "types.h"
-
-void test() {
- // LWG4096
- {
- [[maybe_unused]] auto i1 = std::views::iota(0); // OK
- [[maybe_unused]] auto i2 = std::views::iota(std::views::iota(0));
- // expected-error@*:* {{no matching function for call to object of type 'const __iota::__fn'}}
- }
- {
- [[maybe_unused]] auto i1 = std::views::iota(SomeInt(0)); // OK
- [[maybe_unused]] auto i2 = std::views::iota(std::views::iota(SomeInt(0)));
- //expected-error@*:* {{no matching function for call to object of type 'const __iota::__fn'}}
- }
-}
More information about the libcxx-commits
mailing list