diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -91,7 +91,7 @@ `3544 `__,"``format-arg-store::args`` is unintentionally not exposition-only","June 2021","","","|format|" `3546 `__,"``common_iterator``'s postfix-proxy is not quite right","June 2021","","","|ranges|" `3548 `__,"``shared_ptr`` construction from ``unique_ptr`` should move (not copy) the deleter","June 2021","","" -`3549 `__,"``view_interface`` is overspecified to derive from ``view_base``","June 2021","","","|ranges|" +`3549 `__,"``view_interface`` is overspecified to derive from ``view_base``","June 2021","|Complete|","14.0","|ranges|" `3551 `__,"``borrowed_{iterator,subrange}_t`` are overspecified","June 2021","","","|ranges|" `3552 `__,"Parallel specialized memory algorithms should require forward iterators","June 2021","","" `3553 `__,"Useless constraint in ``split_view::outer-iterator::value_type::begin()``","June 2021","","","|ranges|" diff --git a/libcxx/include/__ranges/enable_view.h b/libcxx/include/__ranges/enable_view.h --- a/libcxx/include/__ranges/enable_view.h +++ b/libcxx/include/__ranges/enable_view.h @@ -25,8 +25,27 @@ struct view_base { }; +template + requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>> +class view_interface; + +template std::true_type __derived_from_view_interface_helper(view_interface<_Tp>*); +std::false_type __derived_from_view_interface_helper(...); + +template +concept __castable_to = requires { + _VSTD::ranges::__derived_from_view_interface_helper(static_cast<_Tp*>(nullptr)); +}; + +template +inline constexpr bool __is_derived_from_view_interface = false; + +template<__castable_to _Tp> +inline constexpr bool __is_derived_from_view_interface<_Tp> = + decltype(_VSTD::ranges::__derived_from_view_interface_helper(static_cast<_Tp*>(nullptr)))::value; + template -inline constexpr bool enable_view = derived_from<_Tp, view_base>; +inline constexpr bool enable_view = derived_from<_Tp, view_base> || _VSTD::ranges::__is_derived_from_view_interface>; } // end namespace ranges diff --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h --- a/libcxx/include/__ranges/view_interface.h +++ b/libcxx/include/__ranges/view_interface.h @@ -40,7 +40,7 @@ template requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>> -class view_interface : public view_base { +class view_interface { _LIBCPP_HIDE_FROM_ABI constexpr _Derived& __derived() noexcept { static_assert(sizeof(_Derived) && derived_from<_Derived, view_interface> && view<_Derived>); 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 --- 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 @@ -46,3 +46,22 @@ // Make sure that enable_view is a bool, not some other contextually-convertible-to-bool type. ASSERT_SAME_TYPE(decltype(std::ranges::enable_view), const bool); ASSERT_SAME_TYPE(decltype(std::ranges::enable_view), const bool); + +struct V1 : std::ranges::view_interface {}; +static_assert(std::ranges::enable_view); +static_assert(std::ranges::enable_view); +static_assert(std::ranges::enable_view); + +struct V2 : std::ranges::view_interface, std::ranges::view_interface {}; +static_assert(!std::ranges::enable_view); +static_assert(!std::ranges::enable_view); +static_assert(!std::ranges::enable_view); + +struct PrivateInherit : private std::ranges::view_interface {}; +static_assert(!std::ranges::enable_view); +static_assert(!std::ranges::enable_view); +static_assert(!std::ranges::enable_view); + +struct Incomplete; +template struct Holder { T t; }; +static_assert(!std::ranges::enable_view*>); diff --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp --- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp +++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp @@ -32,8 +32,6 @@ static_assert(!ValidViewInterfaceType); static_assert( ValidViewInterfaceType); -static_assert(std::derived_from, std::ranges::view_base>); - using InputIter = cpp20_input_iterator; struct InputRange : std::ranges::view_interface { @@ -81,6 +79,10 @@ }; static_assert(std::ranges::view); +struct MultipleInheritanceViewInterface : std::ranges::view_interface, std::ranges::view_interface { +}; +static_assert(!std::ranges::view); + struct EmptyIsTrue : std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; constexpr ForwardIter begin() const { return ForwardIter(const_cast(buff)); } @@ -302,6 +304,10 @@ return true; } +struct V1 : std::ranges::view_interface { }; +struct V2 : std::ranges::view_interface { V1 base_; }; +static_assert(sizeof(V2) == sizeof(V1)); + int main(int, char**) { testEmpty(); static_assert(testEmpty());