[libcxx-commits] [libcxx] [libc++][test] Only `views::split(pattern)` can be piped (PR #74961)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Dec 9 19:02:59 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Stephan T. Lavavej (StephanTLavavej)
<details>
<summary>Changes</summary>
Found while running libc++'s tests with MSVC's STL.
* [N4964](https://isocpp.org/files/papers/N4964.pdf) \[range.split.overview\]/2:
> The name `views::split` denotes a range adaptor object (\[range.adaptor.object\]). Given subexpressions `E` and `F`, the expression `views::split(E, F)` is expression-equivalent to `split_view(E, F)`.
* \[range.lazy.split.overview\]/2:
> The name `views::lazy_split` denotes a range adaptor object (\[range.adaptor.object\]). Given subexpressions `E` and `F`, the expression `views::lazy_split(E, F)` is expression-equivalent to `lazy_split_view(E, F)`.
* \[range.adaptor.object\]/1:
> A *range adaptor closure object* is a unary function object that accepts a range argument. For a range adaptor
closure object `C` and an expression `R` such that `decltype((R))` models `range`, the following expressions are
equivalent:
> `C(R)`
> `R | C`
* \[range.adaptor.object\]/6-8:
> A *range adaptor object* is a customization point object (\[customization.point.object\]) that accepts a `viewable_range` as its first argument and returns a view.
> If a range adaptor object accepts only one argument, then it is a range adaptor closure object.
> If a range adaptor object `adaptor` accepts more than one argument, then let `range` be an expression such that `decltype((range))` models `viewable_range`, let `args...` be arguments such that `adaptor(range, args...)` is a well-formed expression as specified in the rest of subclause \[range.adaptors\], and let `BoundArgs` be a pack that denotes `decay_t<decltype((args))>...`. The expression `adaptor(args...)` produces a range adaptor closure object `f` that is a perfect forwarding call wrapper (\[func.require\]) with the following properties: \[...\]
To summarize: `views::split` and `views::lazy_split` aren't unary, aren't range adaptor **closure** objects, and can't be piped. However, \[range.adaptor.object\]/8 says that `views::split(pattern)` and `views::lazy_split(pattern)` produce unary, pipeable, range adaptor closure objects.
This PR adjusts the test coverage accordingly.
Note: The fact that the tests were previously passing may indicate the existence of a bug (or an extension?) in libc++'s product code. I looked at the machinery briefly but it was far beyond me (I barely understand microsoft/STL's ranges machinery). As this PR changes the tests to be portable, I would like to request that if changes to libc++'s product code are desired, that should be done in a followup PR (and I can file a followup issue if a reminder is desired).
<details><summary>Click to expand the Clang compiler error that discovered this:</summary>
```
D:\GitHub\STL\llvm-project\libcxx\test\std\ranges\range.adaptors\range.split\adaptor.pass.cpp(42,1): error: static assertion failed
static_assert( CanBePiped<SomeView&, decltype(std::views::split)>);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
D:\GitHub\STL\llvm-project\libcxx\test\std\ranges\range.adaptors\range.split\adaptor.pass.cpp(42,16): note: because 'CanBePiped<SomeView &, decltype(std::views::split)>' evaluated to false
static_assert( CanBePiped<SomeView&, decltype(std::views::split)>);
^
D:\GitHub\STL\llvm-project\libcxx\test\std\ranges\range.adaptors\range.split\adaptor.pass.cpp(25,30): note: because 'std::forward<View>(view) | std::forward<T>(t)' would be invalid: invalid operands to binary expression ('SomeView' and 'const std::ranges::views::_Split_fn')
{ std::forward<View>(view) | std::forward<T>(t) };
^
D:\GitHub\STL\llvm-project\libcxx\test\std\ranges\range.adaptors\range.split\adaptor.pass.cpp(43,1): error: static assertion failed
static_assert( CanBePiped<char(&)[10], decltype(std::views::split)>);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
D:\GitHub\STL\llvm-project\libcxx\test\std\ranges\range.adaptors\range.split\adaptor.pass.cpp(43,16): note: because 'CanBePiped<char (&)[10], decltype(std::views::split)>' evaluated to false
static_assert( CanBePiped<char(&)[10], decltype(std::views::split)>);
^
D:\GitHub\STL\llvm-project\libcxx\test\std\ranges\range.adaptors\range.split\adaptor.pass.cpp(25,30): note: because 'std::forward<View>(view) | std::forward<T>(t)' would be invalid: invalid operands to binary expression ('char[10]' and 'const std::ranges::views::_Split_fn')
{ std::forward<View>(view) | std::forward<T>(t) };
^
```
</details>
---
Full diff: https://github.com/llvm/llvm-project/pull/74961.diff
2 Files Affected:
- (modified) libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp (+4-4)
- (modified) libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp (+4-4)
``````````diff
diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp
index da4bd9fbbe1794..58be3713263c73 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp
@@ -40,10 +40,10 @@ static_assert(!std::is_invocable_v<decltype(std::views::lazy_split), SomeView, N
static_assert(!std::is_invocable_v<decltype(std::views::lazy_split), NotAView, SomeView>);
static_assert( std::is_invocable_v<decltype(std::views::lazy_split), SomeView, SomeView>);
-static_assert( CanBePiped<SomeView&, decltype(std::views::lazy_split)>);
-static_assert( CanBePiped<char(&)[10], decltype(std::views::lazy_split)>);
-static_assert(!CanBePiped<char(&&)[10], decltype(std::views::lazy_split)>);
-static_assert(!CanBePiped<NotAView, decltype(std::views::lazy_split)>);
+static_assert( CanBePiped<SomeView&, decltype(std::views::lazy_split('x'))>);
+static_assert( CanBePiped<char(&)[10], decltype(std::views::lazy_split('x'))>);
+static_assert(!CanBePiped<char(&&)[10], decltype(std::views::lazy_split('x'))>);
+static_assert(!CanBePiped<NotAView, decltype(std::views::lazy_split('x'))>);
static_assert(std::same_as<decltype(std::views::lazy_split), decltype(std::ranges::views::lazy_split)>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp
index cd12011daeab5d..4b13d1b361198f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp
@@ -39,10 +39,10 @@ static_assert(!std::is_invocable_v<decltype(std::views::split), SomeView, NotAVi
static_assert(!std::is_invocable_v<decltype(std::views::split), NotAView, SomeView>);
static_assert( std::is_invocable_v<decltype(std::views::split), SomeView, SomeView>);
-static_assert( CanBePiped<SomeView&, decltype(std::views::split)>);
-static_assert( CanBePiped<char(&)[10], decltype(std::views::split)>);
-static_assert(!CanBePiped<char(&&)[10], decltype(std::views::split)>);
-static_assert(!CanBePiped<NotAView, decltype(std::views::split)>);
+static_assert( CanBePiped<SomeView&, decltype(std::views::split('x'))>);
+static_assert( CanBePiped<char(&)[10], decltype(std::views::split('x'))>);
+static_assert(!CanBePiped<char(&&)[10], decltype(std::views::split('x'))>);
+static_assert(!CanBePiped<NotAView, decltype(std::views::split('x'))>);
static_assert(std::same_as<decltype(std::views::split), decltype(std::ranges::views::split)>);
``````````
</details>
https://github.com/llvm/llvm-project/pull/74961
More information about the libcxx-commits
mailing list