Skip to content

Commit 3c0300d

Browse files
[libc++][ranges] Adjust inheritance detection for enable_view (#132582)
Per [range.view]/6, a `view_interface` isn't a base class of itself, so `enable_view` should report `false`. Also, current implementation strategy handles `const` but not `volatile`, IIUC cv-qualifiers should be consistent handled. In `enable_view.compile.pass.cpp`, coverage for (`const`) `volatile` types are added. Drive-by: Remove one unnessary `test_macro.h` inclusion in a test. Fixes #132577.
1 parent f9aa7a2 commit 3c0300d

File tree

3 files changed

+162
-6
lines changed

3 files changed

+162
-6
lines changed

libcxx/include/__ranges/enable_view.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <__concepts/same_as.h>
1515
#include <__config>
1616
#include <__type_traits/is_class.h>
17-
#include <__type_traits/is_convertible.h>
1817
#include <__type_traits/remove_cv.h>
1918

2019
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -34,12 +33,12 @@ template <class _Derived>
3433
class view_interface;
3534

3635
template <class _Op, class _Yp>
37-
requires is_convertible_v<_Op*, view_interface<_Yp>*>
38-
void __is_derived_from_view_interface(const _Op*, const view_interface<_Yp>*);
36+
requires(!same_as<_Op, view_interface<_Yp>>)
37+
void __is_derived_from_view_interface(view_interface<_Yp>*);
3938

4039
template <class _Tp>
4140
inline constexpr bool enable_view = derived_from<_Tp, view_base> || requires {
42-
ranges::__is_derived_from_view_interface((_Tp*)nullptr, (_Tp*)nullptr);
41+
ranges::__is_derived_from_view_interface<remove_cv_t<_Tp>>((remove_cv_t<_Tp>*)nullptr);
4342
};
4443

4544
} // namespace ranges

libcxx/test/std/ranges/range.req/range.view/enable_view.compile.pass.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ static_assert(!std::ranges::enable_view<Empty&&>);
2525
static_assert(!std::ranges::enable_view<const Empty>);
2626
static_assert(!std::ranges::enable_view<const Empty&>);
2727
static_assert(!std::ranges::enable_view<const Empty&&>);
28+
static_assert(!std::ranges::enable_view<volatile Empty>);
29+
static_assert(!std::ranges::enable_view<volatile Empty&>);
30+
static_assert(!std::ranges::enable_view<volatile Empty&&>);
31+
static_assert(!std::ranges::enable_view<const volatile Empty>);
32+
static_assert(!std::ranges::enable_view<const volatile Empty&>);
33+
static_assert(!std::ranges::enable_view<const volatile Empty&&>);
2834

2935
// Derives from view_base, but privately
3036
struct PrivateViewBase : private std::ranges::view_base { };
@@ -34,6 +40,12 @@ static_assert(!std::ranges::enable_view<PrivateViewBase&&>);
3440
static_assert(!std::ranges::enable_view<const PrivateViewBase>);
3541
static_assert(!std::ranges::enable_view<const PrivateViewBase&>);
3642
static_assert(!std::ranges::enable_view<const PrivateViewBase&&>);
43+
static_assert(!std::ranges::enable_view<volatile PrivateViewBase>);
44+
static_assert(!std::ranges::enable_view<volatile PrivateViewBase&>);
45+
static_assert(!std::ranges::enable_view<volatile PrivateViewBase&&>);
46+
static_assert(!std::ranges::enable_view<const volatile PrivateViewBase>);
47+
static_assert(!std::ranges::enable_view<const volatile PrivateViewBase&>);
48+
static_assert(!std::ranges::enable_view<const volatile PrivateViewBase&&>);
3749

3850
// Derives from view_base, but specializes enable_view to false
3951
struct EnableViewFalse : std::ranges::view_base { };
@@ -44,6 +56,12 @@ static_assert(!std::ranges::enable_view<EnableViewFalse&&>);
4456
static_assert(std::ranges::enable_view<const EnableViewFalse>);
4557
static_assert(!std::ranges::enable_view<const EnableViewFalse&>);
4658
static_assert(!std::ranges::enable_view<const EnableViewFalse&&>);
59+
static_assert(std::ranges::enable_view<volatile EnableViewFalse>);
60+
static_assert(!std::ranges::enable_view<volatile EnableViewFalse&>);
61+
static_assert(!std::ranges::enable_view<volatile EnableViewFalse&&>);
62+
static_assert(std::ranges::enable_view<const volatile EnableViewFalse>);
63+
static_assert(!std::ranges::enable_view<const volatile EnableViewFalse&>);
64+
static_assert(!std::ranges::enable_view<const volatile EnableViewFalse&&>);
4765

4866
// Derives from view_base
4967
struct PublicViewBase : std::ranges::view_base { };
@@ -53,6 +71,12 @@ static_assert(!std::ranges::enable_view<PublicViewBase&&>);
5371
static_assert(std::ranges::enable_view<const PublicViewBase>);
5472
static_assert(!std::ranges::enable_view<const PublicViewBase&>);
5573
static_assert(!std::ranges::enable_view<const PublicViewBase&&>);
74+
static_assert(std::ranges::enable_view<volatile PublicViewBase>);
75+
static_assert(!std::ranges::enable_view<volatile PublicViewBase&>);
76+
static_assert(!std::ranges::enable_view<volatile PublicViewBase&&>);
77+
static_assert(std::ranges::enable_view<const volatile PublicViewBase>);
78+
static_assert(!std::ranges::enable_view<const volatile PublicViewBase&>);
79+
static_assert(!std::ranges::enable_view<const volatile PublicViewBase&&>);
5680

5781
// Does not derive from view_base, but specializes enable_view to true
5882
struct EnableViewTrue { };
@@ -63,6 +87,12 @@ static_assert(!std::ranges::enable_view<EnableViewTrue&&>);
6387
static_assert(!std::ranges::enable_view<const EnableViewTrue>);
6488
static_assert(!std::ranges::enable_view<const EnableViewTrue&>);
6589
static_assert(!std::ranges::enable_view<const EnableViewTrue&&>);
90+
static_assert(!std::ranges::enable_view<volatile EnableViewTrue>);
91+
static_assert(!std::ranges::enable_view<volatile EnableViewTrue&>);
92+
static_assert(!std::ranges::enable_view<volatile EnableViewTrue&&>);
93+
static_assert(!std::ranges::enable_view<const volatile EnableViewTrue>);
94+
static_assert(!std::ranges::enable_view<const volatile EnableViewTrue&>);
95+
static_assert(!std::ranges::enable_view<const volatile EnableViewTrue&&>);
6696

6797
// Make sure that enable_view is a bool, not some other contextually-convertible-to-bool type.
6898
ASSERT_SAME_TYPE(decltype(std::ranges::enable_view<Empty>), const bool);
@@ -75,6 +105,12 @@ static_assert(!std::ranges::enable_view<V1&&>);
75105
static_assert(std::ranges::enable_view<const V1>);
76106
static_assert(!std::ranges::enable_view<const V1&>);
77107
static_assert(!std::ranges::enable_view<const V1&&>);
108+
static_assert(std::ranges::enable_view<volatile V1>);
109+
static_assert(!std::ranges::enable_view<volatile V1&>);
110+
static_assert(!std::ranges::enable_view<volatile V1&&>);
111+
static_assert(std::ranges::enable_view<const volatile V1>);
112+
static_assert(!std::ranges::enable_view<const volatile V1&>);
113+
static_assert(!std::ranges::enable_view<const volatile V1&&>);
78114

79115
struct V2 : std::ranges::view_interface<V1>, std::ranges::view_interface<V2> {};
80116
static_assert(!std::ranges::enable_view<V2>);
@@ -83,6 +119,12 @@ static_assert(!std::ranges::enable_view<V2&&>);
83119
static_assert(!std::ranges::enable_view<const V2>);
84120
static_assert(!std::ranges::enable_view<const V2&>);
85121
static_assert(!std::ranges::enable_view<const V2&&>);
122+
static_assert(!std::ranges::enable_view<volatile V2>);
123+
static_assert(!std::ranges::enable_view<volatile V2&>);
124+
static_assert(!std::ranges::enable_view<volatile V2&&>);
125+
static_assert(!std::ranges::enable_view<const volatile V2>);
126+
static_assert(!std::ranges::enable_view<const volatile V2&>);
127+
static_assert(!std::ranges::enable_view<const volatile V2&&>);
86128

87129
struct V3 : std::ranges::view_interface<V1> {};
88130
static_assert(std::ranges::enable_view<V3>);
@@ -91,13 +133,35 @@ static_assert(!std::ranges::enable_view<V3&&>);
91133
static_assert(std::ranges::enable_view<const V3>);
92134
static_assert(!std::ranges::enable_view<const V3&>);
93135
static_assert(!std::ranges::enable_view<const V3&&>);
136+
static_assert(std::ranges::enable_view<volatile V3>);
137+
static_assert(!std::ranges::enable_view<volatile V3&>);
138+
static_assert(!std::ranges::enable_view<volatile V3&&>);
139+
static_assert(std::ranges::enable_view<const volatile V3>);
140+
static_assert(!std::ranges::enable_view<const volatile V3&>);
141+
static_assert(!std::ranges::enable_view<const volatile V3&&>);
94142

95143
struct PrivateInherit : private std::ranges::view_interface<PrivateInherit> {};
96144
static_assert(!std::ranges::enable_view<PrivateInherit>);
145+
static_assert(!std::ranges::enable_view<const PrivateInherit>);
146+
static_assert(!std::ranges::enable_view<volatile PrivateInherit>);
147+
static_assert(!std::ranges::enable_view<const volatile PrivateInherit>);
148+
149+
// https://github.com/llvm/llvm-project/issues/132577
150+
// enable_view<view_interface<T>> should be false.
151+
static_assert(!std::ranges::enable_view<std::ranges::view_interface<V1>>);
152+
static_assert(!std::ranges::enable_view<const std::ranges::view_interface<V1>>);
153+
static_assert(!std::ranges::enable_view<volatile std::ranges::view_interface<V1>>);
154+
static_assert(!std::ranges::enable_view<const volatile std::ranges::view_interface<V1>>);
97155

98156
// ADL-proof
99157
struct Incomplete;
100158
template<class T> struct Holder { T t; };
101159
static_assert(!std::ranges::enable_view<Holder<Incomplete>*>);
160+
static_assert(!std::ranges::enable_view<const Holder<Incomplete>*>);
161+
static_assert(!std::ranges::enable_view<volatile Holder<Incomplete>*>);
162+
static_assert(!std::ranges::enable_view<const volatile Holder<Incomplete>*>);
102163

103164
static_assert(!std::ranges::enable_view<void>);
165+
static_assert(!std::ranges::enable_view<const void>);
166+
static_assert(!std::ranges::enable_view<volatile void>);
167+
static_assert(!std::ranges::enable_view<const volatile void>);

libcxx/test/std/ranges/range.req/range.view/view.compile.pass.cpp

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515

1616
#include <ranges>
1717

18-
#include "test_macros.h"
19-
2018
// The type would be a view, but it's not moveable.
2119
struct NotMoveable : std::ranges::view_base {
2220
NotMoveable() = default;
@@ -90,3 +88,98 @@ static_assert(std::movable<View>);
9088
static_assert(std::default_initializable<View>);
9189
static_assert(std::ranges::enable_view<View>);
9290
static_assert(std::ranges::view<View>);
91+
92+
// const view types
93+
94+
struct ConstView1 : std::ranges::view_base {
95+
ConstView1(const ConstView1&&);
96+
const ConstView1& operator=(const ConstView1&&) const;
97+
98+
friend void swap(const ConstView1&, const ConstView1&);
99+
100+
friend int* begin(const ConstView1&);
101+
friend int* end(const ConstView1&);
102+
};
103+
static_assert(std::ranges::range<const ConstView1>);
104+
static_assert(std::movable<const ConstView1>);
105+
static_assert(!std::default_initializable<const ConstView1>);
106+
static_assert(std::ranges::enable_view<const ConstView1>);
107+
static_assert(std::ranges::view<const ConstView1>);
108+
109+
struct ConstView2 : std::ranges::view_interface<ConstView2> {
110+
ConstView2(const ConstView2&&);
111+
const ConstView2& operator=(const ConstView2&&) const;
112+
113+
friend void swap(const ConstView2&, const ConstView2&);
114+
115+
friend int* begin(const ConstView2&);
116+
friend int* end(const ConstView2&);
117+
};
118+
static_assert(std::ranges::range<const ConstView2>);
119+
static_assert(std::movable<const ConstView2>);
120+
static_assert(!std::default_initializable<const ConstView2>);
121+
static_assert(std::ranges::enable_view<const ConstView2>);
122+
static_assert(std::ranges::view<const ConstView2>);
123+
124+
// volatile view types
125+
struct VolatileView1 : std::ranges::view_base {
126+
VolatileView1(volatile VolatileView1&&);
127+
volatile VolatileView1& operator=(volatile VolatileView1&&) volatile;
128+
129+
friend void swap(volatile VolatileView1&, volatile VolatileView1&);
130+
131+
friend int* begin(volatile VolatileView1&);
132+
friend int* end(volatile VolatileView1&);
133+
};
134+
static_assert(std::ranges::range<volatile VolatileView1>);
135+
static_assert(std::movable<volatile VolatileView1>);
136+
static_assert(!std::default_initializable<volatile VolatileView1>);
137+
static_assert(std::ranges::enable_view<volatile VolatileView1>);
138+
static_assert(std::ranges::view<volatile VolatileView1>);
139+
140+
struct VolatileView2 : std::ranges::view_interface<VolatileView2> {
141+
VolatileView2(volatile VolatileView2&&);
142+
volatile VolatileView2& operator=(volatile VolatileView2&&) volatile;
143+
144+
friend void swap(volatile VolatileView2&, volatile VolatileView2&);
145+
146+
friend int* begin(volatile VolatileView2&);
147+
friend int* end(volatile VolatileView2&);
148+
};
149+
static_assert(std::ranges::range<volatile VolatileView2>);
150+
static_assert(std::movable<volatile VolatileView2>);
151+
static_assert(!std::default_initializable<volatile VolatileView2>);
152+
static_assert(std::ranges::enable_view<volatile VolatileView2>);
153+
static_assert(std::ranges::view<volatile VolatileView2>);
154+
155+
// const-volatile view types
156+
157+
struct ConstVolatileView1 : std::ranges::view_base {
158+
ConstVolatileView1(const volatile ConstVolatileView1&&);
159+
const volatile ConstVolatileView1& operator=(const volatile ConstVolatileView1&&) const volatile;
160+
161+
friend void swap(const volatile ConstVolatileView1&, const volatile ConstVolatileView1&);
162+
163+
friend int* begin(const volatile ConstVolatileView1&);
164+
friend int* end(const volatile ConstVolatileView1&);
165+
};
166+
static_assert(std::ranges::range<const volatile ConstVolatileView1>);
167+
static_assert(std::movable<const volatile ConstVolatileView1>);
168+
static_assert(!std::default_initializable<const volatile ConstVolatileView1>);
169+
static_assert(std::ranges::enable_view<const volatile ConstVolatileView1>);
170+
static_assert(std::ranges::view<const volatile ConstVolatileView1>);
171+
172+
struct ConstVolatileView2 : std::ranges::view_interface<ConstVolatileView2> {
173+
ConstVolatileView2(const volatile ConstVolatileView2&&);
174+
const volatile ConstVolatileView2& operator=(const volatile ConstVolatileView2&&) const volatile;
175+
176+
friend void swap(const volatile ConstVolatileView2&, const volatile ConstVolatileView2&);
177+
178+
friend int* begin(const volatile ConstVolatileView2&);
179+
friend int* end(const volatile ConstVolatileView2&);
180+
};
181+
static_assert(std::ranges::range<const volatile ConstVolatileView2>);
182+
static_assert(std::movable<const volatile ConstVolatileView2>);
183+
static_assert(!std::default_initializable<const volatile ConstVolatileView2>);
184+
static_assert(std::ranges::enable_view<const volatile ConstVolatileView2>);
185+
static_assert(std::ranges::view<const volatile ConstVolatileView2>);

0 commit comments

Comments
 (0)