Skip to content

[libc++][ranges] Adjust inheritance detection for enable_view #132582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions libcxx/include/__ranges/enable_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 { };
Expand All @@ -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 { };
Expand All @@ -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 { };
Expand All @@ -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 { };
Expand All @@ -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);
Expand All @@ -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>);
Expand All @@ -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>);
Expand All @@ -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>);
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>);