diff options
13 files changed, 162 insertions, 279 deletions
diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h index b0b89c0..d54b331 100644 --- a/libcxx/include/__ranges/access.h +++ b/libcxx/include/__ranges/access.h @@ -27,15 +27,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if !defined(_LIBCPP_HAS_NO_RANGES) -// clang-format off - namespace ranges { template <class _Tp> concept __can_borrow = is_lvalue_reference_v<_Tp> || enable_borrowed_range<remove_cvref_t<_Tp> >; - - template<class _Tp> - concept __is_complete = requires { sizeof(_Tp); }; } // namespace ranges // [range.access.begin] @@ -61,15 +56,10 @@ namespace ranges::__begin { struct __fn { template <class _Tp> - requires is_array_v<remove_cv_t<_Tp>> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp& __t) const noexcept { - constexpr bool __complete = __is_complete<iter_value_t<_Tp> >; - if constexpr (__complete) { // used to disable cryptic diagnostic - return __t + 0; - } - else { - static_assert(__complete, "`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."); - } + requires is_array_v<remove_cv_t<_Tp>> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp& __t) const noexcept + { + return __t; } template <class _Tp> @@ -127,14 +117,10 @@ namespace ranges::__end { class __fn { public: template <class _Tp, size_t _Np> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept { - constexpr bool __complete = __is_complete<remove_cv_t<_Tp> >; - if constexpr (__complete) { // used to disable cryptic diagnostic - return __t + _Np; - } - else { - static_assert(__complete, "`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."); - } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept + requires (sizeof(*__t) != 0) // Disallow incomplete element types. + { + return __t + _Np; } template <class _Tp> @@ -209,8 +195,6 @@ namespace ranges::inline __cpo { inline constexpr auto cend = __cend::__fn{}; } // namespace ranges::__cpo -// clang-format off - #endif // !defined(_LIBCPP_HAS_NO_RANGES) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/ranges/range.access/begin.incomplete_type.sh.cpp b/libcxx/test/libcxx/ranges/range.access/begin.incomplete_type.sh.cpp new file mode 100644 index 0000000..0bf3599 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.access/begin.incomplete_type.sh.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// RUN: %{cxx} %{flags} %{compile_flags} -c %s -o %t.tu1.o -DTU1 +// RUN: %{cxx} %{flags} %{compile_flags} -c %s -o %t.tu2.o -DTU2 +// RUN: %{cxx} %t.tu1.o %t.tu2.o %{flags} %{link_flags} -o %t.exe +// RUN: %{exec} %t.exe + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// Test the libc++-specific behavior that we handle the IFNDR case for ranges::begin +// by returning the beginning of the array-of-incomplete-type. +// Use two translation units so that `Incomplete` really is never completed +// at any point within TU2, but the array `bounded` is still given a definition +// (in TU1) to avoid an "undefined reference" error from the linker. +// All of the actually interesting stuff takes place within TU2. + +#include <ranges> +#include <cassert> + +#include "test_macros.h" + +#if defined(TU1) + +struct Incomplete {}; +Incomplete bounded[10]; +Incomplete unbounded[10]; + +#else // defined(TU1) + +struct Incomplete; + +constexpr bool test() +{ + { + extern Incomplete bounded[10]; + assert(std::ranges::begin(bounded) == bounded); + assert(std::ranges::cbegin(bounded) == bounded); + assert(std::ranges::begin(std::as_const(bounded)) == bounded); + assert(std::ranges::cbegin(std::as_const(bounded)) == bounded); + ASSERT_SAME_TYPE(decltype(std::ranges::begin(bounded)), Incomplete*); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(bounded)), const Incomplete*); + ASSERT_SAME_TYPE(decltype(std::ranges::begin(std::as_const(bounded))), const Incomplete*); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(std::as_const(bounded))), const Incomplete*); + } + { + extern Incomplete unbounded[]; + assert(std::ranges::begin(unbounded) == unbounded); + assert(std::ranges::cbegin(unbounded) == unbounded); + assert(std::ranges::begin(std::as_const(unbounded)) == unbounded); + assert(std::ranges::cbegin(std::as_const(unbounded)) == unbounded); + ASSERT_SAME_TYPE(decltype(std::ranges::begin(unbounded)), Incomplete*); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(unbounded)), const Incomplete*); + ASSERT_SAME_TYPE(decltype(std::ranges::begin(std::as_const(unbounded))), const Incomplete*); + ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(std::as_const(unbounded))), const Incomplete*); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); +} + +#endif // defined(TU1) diff --git a/libcxx/test/libcxx/ranges/range.access/end.incomplete_type.pass.cpp b/libcxx/test/libcxx/ranges/range.access/end.incomplete_type.pass.cpp new file mode 100644 index 0000000..4b83ca8 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.access/end.incomplete_type.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// Test the libc++-specific behavior that we handle the IFNDR case for ranges::end +// by being SFINAE-friendly. + +#include <ranges> +#include <cassert> +#include <type_traits> + +struct Incomplete; + +constexpr bool test() +{ + { + extern Incomplete bounded[10]; + assert((!std::is_invocable_v<decltype(std::ranges::end), decltype((bounded))>)); + assert((!std::is_invocable_v<decltype(std::ranges::cend), decltype((bounded))>)); + assert((!std::is_invocable_v<decltype(std::ranges::end), decltype(std::as_const(bounded))>)); + assert((!std::is_invocable_v<decltype(std::ranges::cend), decltype(std::as_const(bounded))>)); + } + { + extern Incomplete unbounded[]; + assert((!std::is_invocable_v<decltype(std::ranges::end), decltype((unbounded))>)); + assert((!std::is_invocable_v<decltype(std::ranges::cend), decltype((unbounded))>)); + assert((!std::is_invocable_v<decltype(std::ranges::end), decltype(std::as_const(unbounded))>)); + assert((!std::is_invocable_v<decltype(std::ranges::cend), decltype(std::as_const(unbounded))>)); + } + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); +} diff --git a/libcxx/test/libcxx/ranges/range.access/range.access.begin/incomplete.verify.cpp b/libcxx/test/libcxx/ranges/range.access/range.access.begin/incomplete.verify.cpp deleted file mode 100644 index 4132252..0000000 --- a/libcxx/test/libcxx/ranges/range.access/range.access.begin/incomplete.verify.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::begin on an array of incomplete type. - -#include <ranges> - -#include <type_traits> - -using begin_t = decltype(std::ranges::begin); - -template <class T> void f() requires std::invocable<begin_t&, T> { } -template <class T> void f() { } - -void test() { - struct incomplete; - f<incomplete(&)[]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - f<incomplete(&)[10]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - f<incomplete(&)[2][2]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - - // This is okay because calling `std::ranges::begin` on any rvalue is ill-formed. - f<incomplete(&&)[10]>(); -} diff --git a/libcxx/test/libcxx/ranges/range.access/range.access.cbegin/incomplete.verify.cpp b/libcxx/test/libcxx/ranges/range.access/range.access.cbegin/incomplete.verify.cpp deleted file mode 100644 index bd0ff5e..0000000 --- a/libcxx/test/libcxx/ranges/range.access/range.access.cbegin/incomplete.verify.cpp +++ /dev/null @@ -1,32 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::cbegin on an array of incomplete type. - -#include <ranges> - -#include <type_traits> - -using cbegin_t = decltype(std::ranges::cbegin); - -template <class T> void f() requires std::invocable<cbegin_t&, T> { } -template <class T> void f() { } - -void test() { - struct incomplete; - f<incomplete(&)[10]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - - // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. - f<incomplete(&&)[10]>(); -} diff --git a/libcxx/test/libcxx/ranges/range.access/range.access.cend/incomplete.verify.cpp b/libcxx/test/libcxx/ranges/range.access/range.access.cend/incomplete.verify.cpp deleted file mode 100644 index b4d6729..0000000 --- a/libcxx/test/libcxx/ranges/range.access/range.access.cend/incomplete.verify.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::cend on an array of incomplete type. - -#include <ranges> - -#include <type_traits> - -using cend_t = decltype(std::ranges::cend); - -template <class T> void f() requires std::invocable<cend_t&, T> { } -template <class T> void f() { } - -void test() { - struct incomplete; - f<incomplete(&)[]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}} - f<incomplete(&)[10]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}} - f<incomplete(&)[2][2]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - - // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. - f<incomplete(&&)[10]>(); -} diff --git a/libcxx/test/libcxx/ranges/range.access/range.access.end/incomplete.verify.cpp b/libcxx/test/libcxx/ranges/range.access/range.access.end/incomplete.verify.cpp deleted file mode 100644 index ecfe1c4..0000000 --- a/libcxx/test/libcxx/ranges/range.access/range.access.end/incomplete.verify.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::end on an array of incomplete type. - -#include <ranges> - -#include <type_traits> - -using end_t = decltype(std::ranges::end); - -template <class T> void f() requires std::invocable<end_t&, T> { } -template <class T> void f() { } - -void test() { - struct incomplete; - f<incomplete(&)[]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}} - f<incomplete(&)[10]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}} - f<incomplete(&)[2][2]>(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - - // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. - f<incomplete(&&)[10]>(); -} diff --git a/libcxx/test/libcxx/ranges/range.access/range.prim/data.incomplete.verify.cpp b/libcxx/test/libcxx/ranges/range.access/range.prim/data.incomplete.verify.cpp deleted file mode 100644 index f673280..0000000 --- a/libcxx/test/libcxx/ranges/range.access/range.prim/data.incomplete.verify.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::data on an array of incomplete type. - -#include <ranges> - -struct Incomplete; - -void f(Incomplete arr[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&arr)[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&&arr)[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f2(Incomplete arr[2]) { - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&arr)[2]) { - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&&arr)[2]) { - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&arr)[2][2]) { - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} diff --git a/libcxx/test/libcxx/ranges/range.access/range.prim/empty.incomplete.verify.cpp b/libcxx/test/libcxx/ranges/range.access/range.prim/empty.incomplete.verify.cpp deleted file mode 100644 index 3b5f79a5..0000000 --- a/libcxx/test/libcxx/ranges/range.access/range.prim/empty.incomplete.verify.cpp +++ /dev/null @@ -1,53 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::empty on an array of incomplete type. - -#include <ranges> - -struct Incomplete; - -void f(Incomplete arr[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - // expected-error@*:* {{call to deleted function call operator in type}} - // expected-error@*:* {{attempt to use a deleted function}} - std::ranges::begin(arr); -} - -void f(Incomplete(&arr)[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - std::ranges::begin(arr); -} - -void f(Incomplete(&&arr)[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - std::ranges::begin(arr); -} - -void f2(Incomplete arr[2]) { - // expected-error@*:* {{call to deleted function call operator in type}} - // expected-error@*:* {{attempt to use a deleted function}} - std::ranges::begin(arr); -} - -void f(Incomplete(&arr)[2]) { - std::ranges::begin(arr); -} - -void f(Incomplete(&&arr)[2]) { - std::ranges::begin(arr); -} - -void f(Incomplete(&arr)[2][2]) { - std::ranges::begin(arr); -} diff --git a/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp index 3b712a1..05e6211 100644 --- a/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp @@ -23,13 +23,17 @@ using RangeCBeginT = decltype(std::ranges::cbegin)&; static int globalBuff[8]; -struct Incomplete; - static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[10]>); static_assert( std::is_invocable_v<RangeBeginT, int (&)[10]>); static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[]>); static_assert( std::is_invocable_v<RangeBeginT, int (&)[]>); +struct Incomplete; +static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[]>); +static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[42]>); +static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>); +static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[42]>); + struct BeginMember { int x; constexpr const int *begin() const { return &x; } diff --git a/libcxx/test/std/ranges/range.access/range.access.end/end.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.end/end.pass.cpp index dd5da2e..1e4fc02 100644 --- a/libcxx/test/std/ranges/range.access/range.access.end/end.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.access.end/end.pass.cpp @@ -28,6 +28,12 @@ static_assert(!std::is_invocable_v<RangeEndT, int (&)[]>); static_assert(!std::is_invocable_v<RangeEndT, int (&&)[10]>); static_assert( std::is_invocable_v<RangeEndT, int (&)[10]>); +struct Incomplete; +static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[]>); +static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[42]>); +static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>); +static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[42]>); + struct EndMember { int x; constexpr const int *begin() const { return nullptr; } diff --git a/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp b/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp index 5a06fa8..9be523e 100644 --- a/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp @@ -30,6 +30,17 @@ static_assert( std::is_invocable_v<RangeEmptyT, int (&&)[1]>); static_assert( std::is_invocable_v<RangeEmptyT, int (&)[1]>); static_assert( std::is_invocable_v<RangeEmptyT, const int (&)[1]>); +struct Incomplete; +static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete[]>); +static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete(&)[]>); +static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete(&&)[]>); + +extern Incomplete array_of_incomplete[42]; +static_assert(!std::ranges::empty(array_of_incomplete)); +static_assert(!std::ranges::empty(std::move(array_of_incomplete))); +static_assert(!std::ranges::empty(std::as_const(array_of_incomplete))); +static_assert(!std::ranges::empty(static_cast<const Incomplete(&&)[42]>(array_of_incomplete))); + struct NonConstSizeAndEmpty { int size(); bool empty(); diff --git a/libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp b/libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp index 1744974..92023cc 100644 --- a/libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp @@ -25,6 +25,17 @@ static_assert( std::is_invocable_v<RangeSizeT, int[1]>); static_assert( std::is_invocable_v<RangeSizeT, int (&&)[1]>); static_assert( std::is_invocable_v<RangeSizeT, int (&)[1]>); +struct Incomplete; +static_assert(!std::is_invocable_v<RangeSizeT, Incomplete[]>); +static_assert(!std::is_invocable_v<RangeSizeT, Incomplete(&)[]>); +static_assert(!std::is_invocable_v<RangeSizeT, Incomplete(&&)[]>); + +extern Incomplete array_of_incomplete[42]; +static_assert(std::ranges::size(array_of_incomplete) == 42); +static_assert(std::ranges::size(std::move(array_of_incomplete)) == 42); +static_assert(std::ranges::size(std::as_const(array_of_incomplete)) == 42); +static_assert(std::ranges::size(static_cast<const Incomplete(&&)[42]>(array_of_incomplete)) == 42); + static_assert(std::semiregular<std::remove_cv_t<RangeSizeT>>); struct SizeMember { |