[libcxx-commits] [libcxx] [libc++][ranges] Adjust inheritance detection for `enable_view` (PR #132582)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Mar 22 20:29:43 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: A. Jiang (frederick-vs-ja)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/132582.diff
3 Files Affected:
- (modified) libcxx/include/__ranges/enable_view.h (+3-4)
- (modified) libcxx/test/std/ranges/range.req/range.view/enable_view.compile.pass.cpp (+64)
- (modified) libcxx/test/std/ranges/range.req/range.view/view.compile.pass.cpp (+95-2)
``````````diff
diff --git a/libcxx/include/__ranges/enable_view.h b/libcxx/include/__ranges/enable_view.h
index f570926eb67c3..6dee6ea3fa3d2 100644
--- a/libcxx/include/__ranges/enable_view.h
+++ b/libcxx/include/__ranges/enable_view.h
@@ -14,7 +14,6 @@
#include <__concepts/same_as.h>
#include <__config>
#include <__type_traits/is_class.h>
-#include <__type_traits/is_convertible.h>
#include <__type_traits/remove_cv.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -34,12 +33,12 @@ template <class _Derived>
class view_interface;
template <class _Op, class _Yp>
- requires is_convertible_v<_Op*, view_interface<_Yp>*>
-void __is_derived_from_view_interface(const _Op*, const view_interface<_Yp>*);
+ requires(!same_as<_Op, view_interface<_Yp>>)
+void __is_derived_from_view_interface(view_interface<_Yp>*);
template <class _Tp>
inline constexpr bool enable_view = derived_from<_Tp, view_base> || requires {
- ranges::__is_derived_from_view_interface((_Tp*)nullptr, (_Tp*)nullptr);
+ ranges::__is_derived_from_view_interface<remove_cv_t<_Tp>>((remove_cv_t<_Tp>*)nullptr);
};
} // namespace ranges
diff --git a/libcxx/test/std/ranges/range.req/range.view/enable_view.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.view/enable_view.compile.pass.cpp
index 6412234dce048..202b5bba451ce 100644
--- a/libcxx/test/std/ranges/range.req/range.view/enable_view.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.req/range.view/enable_view.compile.pass.cpp
@@ -25,6 +25,12 @@ static_assert(!std::ranges::enable_view<Empty&&>);
static_assert(!std::ranges::enable_view<const Empty>);
static_assert(!std::ranges::enable_view<const Empty&>);
static_assert(!std::ranges::enable_view<const Empty&&>);
+static_assert(!std::ranges::enable_view<volatile Empty>);
+static_assert(!std::ranges::enable_view<volatile Empty&>);
+static_assert(!std::ranges::enable_view<volatile Empty&&>);
+static_assert(!std::ranges::enable_view<const volatile Empty>);
+static_assert(!std::ranges::enable_view<const volatile Empty&>);
+static_assert(!std::ranges::enable_view<const volatile Empty&&>);
// Derives from view_base, but privately
struct PrivateViewBase : private std::ranges::view_base { };
@@ -34,6 +40,12 @@ static_assert(!std::ranges::enable_view<PrivateViewBase&&>);
static_assert(!std::ranges::enable_view<const PrivateViewBase>);
static_assert(!std::ranges::enable_view<const PrivateViewBase&>);
static_assert(!std::ranges::enable_view<const PrivateViewBase&&>);
+static_assert(!std::ranges::enable_view<volatile PrivateViewBase>);
+static_assert(!std::ranges::enable_view<volatile PrivateViewBase&>);
+static_assert(!std::ranges::enable_view<volatile PrivateViewBase&&>);
+static_assert(!std::ranges::enable_view<const volatile PrivateViewBase>);
+static_assert(!std::ranges::enable_view<const volatile PrivateViewBase&>);
+static_assert(!std::ranges::enable_view<const volatile PrivateViewBase&&>);
// Derives from view_base, but specializes enable_view to false
struct EnableViewFalse : std::ranges::view_base { };
@@ -44,6 +56,12 @@ static_assert(!std::ranges::enable_view<EnableViewFalse&&>);
static_assert(std::ranges::enable_view<const EnableViewFalse>);
static_assert(!std::ranges::enable_view<const EnableViewFalse&>);
static_assert(!std::ranges::enable_view<const EnableViewFalse&&>);
+static_assert(std::ranges::enable_view<volatile EnableViewFalse>);
+static_assert(!std::ranges::enable_view<volatile EnableViewFalse&>);
+static_assert(!std::ranges::enable_view<volatile EnableViewFalse&&>);
+static_assert(std::ranges::enable_view<const volatile EnableViewFalse>);
+static_assert(!std::ranges::enable_view<const volatile EnableViewFalse&>);
+static_assert(!std::ranges::enable_view<const volatile EnableViewFalse&&>);
// Derives from view_base
struct PublicViewBase : std::ranges::view_base { };
@@ -53,6 +71,12 @@ static_assert(!std::ranges::enable_view<PublicViewBase&&>);
static_assert(std::ranges::enable_view<const PublicViewBase>);
static_assert(!std::ranges::enable_view<const PublicViewBase&>);
static_assert(!std::ranges::enable_view<const PublicViewBase&&>);
+static_assert(std::ranges::enable_view<volatile PublicViewBase>);
+static_assert(!std::ranges::enable_view<volatile PublicViewBase&>);
+static_assert(!std::ranges::enable_view<volatile PublicViewBase&&>);
+static_assert(std::ranges::enable_view<const volatile PublicViewBase>);
+static_assert(!std::ranges::enable_view<const volatile PublicViewBase&>);
+static_assert(!std::ranges::enable_view<const volatile PublicViewBase&&>);
// Does not derive from view_base, but specializes enable_view to true
struct EnableViewTrue { };
@@ -63,6 +87,12 @@ static_assert(!std::ranges::enable_view<EnableViewTrue&&>);
static_assert(!std::ranges::enable_view<const EnableViewTrue>);
static_assert(!std::ranges::enable_view<const EnableViewTrue&>);
static_assert(!std::ranges::enable_view<const EnableViewTrue&&>);
+static_assert(!std::ranges::enable_view<volatile EnableViewTrue>);
+static_assert(!std::ranges::enable_view<volatile EnableViewTrue&>);
+static_assert(!std::ranges::enable_view<volatile EnableViewTrue&&>);
+static_assert(!std::ranges::enable_view<const volatile EnableViewTrue>);
+static_assert(!std::ranges::enable_view<const volatile EnableViewTrue&>);
+static_assert(!std::ranges::enable_view<const volatile EnableViewTrue&&>);
// Make sure that enable_view is a bool, not some other contextually-convertible-to-bool type.
ASSERT_SAME_TYPE(decltype(std::ranges::enable_view<Empty>), const bool);
@@ -75,6 +105,12 @@ static_assert(!std::ranges::enable_view<V1&&>);
static_assert(std::ranges::enable_view<const V1>);
static_assert(!std::ranges::enable_view<const V1&>);
static_assert(!std::ranges::enable_view<const V1&&>);
+static_assert(std::ranges::enable_view<volatile V1>);
+static_assert(!std::ranges::enable_view<volatile V1&>);
+static_assert(!std::ranges::enable_view<volatile V1&&>);
+static_assert(std::ranges::enable_view<const volatile V1>);
+static_assert(!std::ranges::enable_view<const volatile V1&>);
+static_assert(!std::ranges::enable_view<const volatile V1&&>);
struct V2 : std::ranges::view_interface<V1>, std::ranges::view_interface<V2> {};
static_assert(!std::ranges::enable_view<V2>);
@@ -83,6 +119,12 @@ static_assert(!std::ranges::enable_view<V2&&>);
static_assert(!std::ranges::enable_view<const V2>);
static_assert(!std::ranges::enable_view<const V2&>);
static_assert(!std::ranges::enable_view<const V2&&>);
+static_assert(!std::ranges::enable_view<volatile V2>);
+static_assert(!std::ranges::enable_view<volatile V2&>);
+static_assert(!std::ranges::enable_view<volatile V2&&>);
+static_assert(!std::ranges::enable_view<const volatile V2>);
+static_assert(!std::ranges::enable_view<const volatile V2&>);
+static_assert(!std::ranges::enable_view<const volatile V2&&>);
struct V3 : std::ranges::view_interface<V1> {};
static_assert(std::ranges::enable_view<V3>);
@@ -91,13 +133,35 @@ static_assert(!std::ranges::enable_view<V3&&>);
static_assert(std::ranges::enable_view<const V3>);
static_assert(!std::ranges::enable_view<const V3&>);
static_assert(!std::ranges::enable_view<const V3&&>);
+static_assert(std::ranges::enable_view<volatile V3>);
+static_assert(!std::ranges::enable_view<volatile V3&>);
+static_assert(!std::ranges::enable_view<volatile V3&&>);
+static_assert(std::ranges::enable_view<const volatile V3>);
+static_assert(!std::ranges::enable_view<const volatile V3&>);
+static_assert(!std::ranges::enable_view<const volatile V3&&>);
struct PrivateInherit : private std::ranges::view_interface<PrivateInherit> {};
static_assert(!std::ranges::enable_view<PrivateInherit>);
+static_assert(!std::ranges::enable_view<const PrivateInherit>);
+static_assert(!std::ranges::enable_view<volatile PrivateInherit>);
+static_assert(!std::ranges::enable_view<const volatile PrivateInherit>);
+
+// https://github.com/llvm/llvm-project/issues/132577
+// enable_view<view_interface<T>> should be false.
+static_assert(!std::ranges::enable_view<std::ranges::view_interface<V1>>);
+static_assert(!std::ranges::enable_view<const std::ranges::view_interface<V1>>);
+static_assert(!std::ranges::enable_view<volatile std::ranges::view_interface<V1>>);
+static_assert(!std::ranges::enable_view<const volatile std::ranges::view_interface<V1>>);
// ADL-proof
struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::ranges::enable_view<Holder<Incomplete>*>);
+static_assert(!std::ranges::enable_view<const Holder<Incomplete>*>);
+static_assert(!std::ranges::enable_view<volatile Holder<Incomplete>*>);
+static_assert(!std::ranges::enable_view<const volatile Holder<Incomplete>*>);
static_assert(!std::ranges::enable_view<void>);
+static_assert(!std::ranges::enable_view<const void>);
+static_assert(!std::ranges::enable_view<volatile void>);
+static_assert(!std::ranges::enable_view<const volatile void>);
diff --git a/libcxx/test/std/ranges/range.req/range.view/view.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.view/view.compile.pass.cpp
index e7a7f30cb20fb..38828cbe46b5b 100644
--- a/libcxx/test/std/ranges/range.req/range.view/view.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.req/range.view/view.compile.pass.cpp
@@ -15,8 +15,6 @@
#include <ranges>
-#include "test_macros.h"
-
// The type would be a view, but it's not moveable.
struct NotMoveable : std::ranges::view_base {
NotMoveable() = default;
@@ -90,3 +88,98 @@ static_assert(std::movable<View>);
static_assert(std::default_initializable<View>);
static_assert(std::ranges::enable_view<View>);
static_assert(std::ranges::view<View>);
+
+// const view types
+
+struct ConstView1 : std::ranges::view_base {
+ ConstView1(const ConstView1&&);
+ const ConstView1& operator=(const ConstView1&&) const;
+
+ friend void swap(const ConstView1&, const ConstView1&);
+
+ friend int* begin(const ConstView1&);
+ friend int* end(const ConstView1&);
+};
+static_assert(std::ranges::range<const ConstView1>);
+static_assert(std::movable<const ConstView1>);
+static_assert(!std::default_initializable<const ConstView1>);
+static_assert(std::ranges::enable_view<const ConstView1>);
+static_assert(std::ranges::view<const ConstView1>);
+
+struct ConstView2 : std::ranges::view_interface<ConstView2> {
+ ConstView2(const ConstView2&&);
+ const ConstView2& operator=(const ConstView2&&) const;
+
+ friend void swap(const ConstView2&, const ConstView2&);
+
+ friend int* begin(const ConstView2&);
+ friend int* end(const ConstView2&);
+};
+static_assert(std::ranges::range<const ConstView2>);
+static_assert(std::movable<const ConstView2>);
+static_assert(!std::default_initializable<const ConstView2>);
+static_assert(std::ranges::enable_view<const ConstView2>);
+static_assert(std::ranges::view<const ConstView2>);
+
+// volatile view types
+struct VolatileView1 : std::ranges::view_base {
+ VolatileView1(volatile VolatileView1&&);
+ volatile VolatileView1& operator=(volatile VolatileView1&&) volatile;
+
+ friend void swap(volatile VolatileView1&, volatile VolatileView1&);
+
+ friend int* begin(volatile VolatileView1&);
+ friend int* end(volatile VolatileView1&);
+};
+static_assert(std::ranges::range<volatile VolatileView1>);
+static_assert(std::movable<volatile VolatileView1>);
+static_assert(!std::default_initializable<volatile VolatileView1>);
+static_assert(std::ranges::enable_view<volatile VolatileView1>);
+static_assert(std::ranges::view<volatile VolatileView1>);
+
+struct VolatileView2 : std::ranges::view_interface<VolatileView2> {
+ VolatileView2(volatile VolatileView2&&);
+ volatile VolatileView2& operator=(volatile VolatileView2&&) volatile;
+
+ friend void swap(volatile VolatileView2&, volatile VolatileView2&);
+
+ friend int* begin(volatile VolatileView2&);
+ friend int* end(volatile VolatileView2&);
+};
+static_assert(std::ranges::range<volatile VolatileView2>);
+static_assert(std::movable<volatile VolatileView2>);
+static_assert(!std::default_initializable<volatile VolatileView2>);
+static_assert(std::ranges::enable_view<volatile VolatileView2>);
+static_assert(std::ranges::view<volatile VolatileView2>);
+
+// const-volatile view types
+
+struct ConstVolatileView1 : std::ranges::view_base {
+ ConstVolatileView1(const volatile ConstVolatileView1&&);
+ const volatile ConstVolatileView1& operator=(const volatile ConstVolatileView1&&) const volatile;
+
+ friend void swap(const volatile ConstVolatileView1&, const volatile ConstVolatileView1&);
+
+ friend int* begin(const volatile ConstVolatileView1&);
+ friend int* end(const volatile ConstVolatileView1&);
+};
+static_assert(std::ranges::range<const volatile ConstVolatileView1>);
+static_assert(std::movable<const volatile ConstVolatileView1>);
+static_assert(!std::default_initializable<const volatile ConstVolatileView1>);
+static_assert(std::ranges::enable_view<const volatile ConstVolatileView1>);
+static_assert(std::ranges::view<const volatile ConstVolatileView1>);
+
+struct ConstVolatileView2 : std::ranges::view_interface<ConstVolatileView2> {
+ ConstVolatileView2(const volatile ConstVolatileView2&&);
+ const volatile ConstVolatileView2& operator=(const volatile ConstVolatileView2&&) const volatile;
+
+ friend void swap(const volatile ConstVolatileView2&, const volatile ConstVolatileView2&);
+
+ friend int* begin(const volatile ConstVolatileView2&);
+ friend int* end(const volatile ConstVolatileView2&);
+};
+static_assert(std::ranges::range<const volatile ConstVolatileView2>);
+static_assert(std::movable<const volatile ConstVolatileView2>);
+static_assert(!std::default_initializable<const volatile ConstVolatileView2>);
+static_assert(std::ranges::enable_view<const volatile ConstVolatileView2>);
+static_assert(std::ranges::view<const volatile ConstVolatileView2>);
``````````
</details>
https://github.com/llvm/llvm-project/pull/132582
More information about the libcxx-commits
mailing list