[libcxx-commits] [libcxx] [libc++][ranges] LWG3984: `ranges::to`'s recursion branch may be ill-formed (PR #87964)
Xiaoyang Liu via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Apr 8 00:28:33 PDT 2024
https://github.com/xiaoyang-sde created https://github.com/llvm/llvm-project/pull/87964
## Abstract
This pull request implements LWG3984: `ranges::to`'s recursion branch may be ill-formed.
In the current implementation, `ranges::to`'s recursion branch pipes the range into a `views::transform(/* lambda */)`, which is a `__range_adaptor_closure` object. In `libc++`, the pipe operator (`operator|`) of `__range_adaptor_closure` requires a `viewable_range`, so the following code won't compile, as the type of lvalue `r` doesn't model `viewable_range`:
```cpp
#include <ranges>
#include <vector>
#include <list>
int main() {
std::vector<std::vector<int>> v;
auto r = std::views::all(std::move(v));
auto l = std::ranges::to<std::list<std::list<int>>>(r);
}
```
## Reference
- [Draft C++ Standard: [range.utility.conv.to] ](https://eel.is/c++draft/range.utility.conv.to)
- [LWG3984](https://cplusplus.github.io/LWG/issue3984)
>From e4e6ae8a50a93d3b41cc15975e9c8c23dfdc7490 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Mon, 8 Apr 2024 00:12:10 -0700
Subject: [PATCH 1/2] [libc++][ranges] LWG3984: 'ranges::to''s recursion branch
may be ill-formed
---
libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
libcxx/include/__ranges/to.h | 2 +-
.../std/ranges/range.utility/range.utility.conv/to.pass.cpp | 5 +++++
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 8a4bf2ef62162a..d91fff7c8687e0 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -44,7 +44,7 @@
"`3919 <https://wg21.link/LWG3919>`__","``enumerate_view`` may invoke UB for sized common non-forward underlying ranges","Tokyo March 2024","","","|ranges|"
"`3950 <https://wg21.link/LWG3950>`__","``std::basic_string_view`` comparison operators are overspecified","Tokyo March 2024","|Complete|","18.0",""
"`3975 <https://wg21.link/LWG3975>`__","Specializations of ``basic_format_context`` should not be permitted","Tokyo March 2024","|Nothing To Do|","","|format|"
-"`3984 <https://wg21.link/LWG3984>`__","``ranges::to``'s recursion branch may be ill-formed","Tokyo March 2024","","","|ranges|"
+"`3984 <https://wg21.link/LWG3984>`__","``ranges::to``'s recursion branch may be ill-formed","Tokyo March 2024","|Complete|","19.0","|ranges|"
"`4011 <https://wg21.link/LWG4011>`__","``""Effects: Equivalent to return""`` in ``[span.elem]``","Tokyo March 2024","|Nothing To Do|","",""
"`4012 <https://wg21.link/LWG4012>`__","``common_view::begin/end`` are missing the ``simple-view`` check","Tokyo March 2024","","","|ranges|"
"`4013 <https://wg21.link/LWG4013>`__","``lazy_split_view::outer-iterator::value_type`` should not provide default constructor","Tokyo March 2024","","","|ranges|"
diff --git a/libcxx/include/__ranges/to.h b/libcxx/include/__ranges/to.h
index 67818c521b1500..014e12a50f6503 100644
--- a/libcxx/include/__ranges/to.h
+++ b/libcxx/include/__ranges/to.h
@@ -129,7 +129,7 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Container to(_Range&& __r
// Try the recursive case.
} else if constexpr (input_range<range_reference_t<_Range>>) {
return ranges::to<_Container>(
- __range | views::transform([](auto&& __elem) {
+ ranges::ref_view(__range) | views::transform([](auto&& __elem) {
return ranges::to<range_value_t<_Container>>(std::forward<decltype(__elem)>(__elem));
}),
std::forward<_Args>(__args)...);
diff --git a/libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp b/libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp
index 3df88d6a2dcc38..7f816bb21a1978 100644
--- a/libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp
@@ -560,6 +560,11 @@ constexpr void test_recursive() {
}
assert((in | std::ranges::to<C4>()) == result);
+
+ // LWG3984: ranges::to's recursion branch may be ill-formed
+ auto in_owning_view = std::views::all(std::move(in));
+ static_assert(!std::ranges::viewable_range<decltype((in_owning_view))>);
+ assert(std::ranges::to<C4>(in_owning_view) == result);
}
constexpr bool test() {
>From a80f564d00d27fe8a1c92a83bf669b6a9da04f35 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Mon, 8 Apr 2024 00:18:15 -0700
Subject: [PATCH 2/2] [libc++][ranges] LWG3984: 'ranges::to''s recursion branch
may be ill-formed
---
libcxx/include/__ranges/to.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/__ranges/to.h b/libcxx/include/__ranges/to.h
index 014e12a50f6503..7d042b196f6a52 100644
--- a/libcxx/include/__ranges/to.h
+++ b/libcxx/include/__ranges/to.h
@@ -24,6 +24,7 @@
#include <__ranges/concepts.h>
#include <__ranges/from_range.h>
#include <__ranges/range_adaptor.h>
+#include <__ranges/ref_view.h>
#include <__ranges/size.h>
#include <__ranges/transform_view.h>
#include <__type_traits/add_pointer.h>
More information about the libcxx-commits
mailing list