diff --git a/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable.pass.cpp b/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable.pass.cpp --- a/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable.pass.cpp +++ b/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable.pass.cpp @@ -24,6 +24,7 @@ #include #include +#include "test_cpo.h" #include "test_macros.h" #include "type_classification/moveconstructible.h" #include "type_classification/swappable.h" @@ -224,6 +225,9 @@ static_assert(std::assignable_from); static_assert(std::swappable); +int arr[2]; +static_assert(test_cpo(std::ranges::swap, arr, arr)); + template void check_swap(expected const& e) { auto a = e.y; diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp --- a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp @@ -20,6 +20,7 @@ #include #include "../unqualified_lookup_wrapper.h" +#include "test_cpo.h" // Wrapper around an iterator for testing `iter_move` when an unqualified call to `iter_move` isn't // possible. @@ -170,6 +171,9 @@ static_assert(noexcept(std::ranges::iter_move(std::declval>()))); static_assert(!noexcept(std::ranges::iter_move(std::declval>()))); + int a[2]; + static_assert(test_cpo(std::ranges::iter_move, a)); + return true; } @@ -177,6 +181,7 @@ concept can_iter_move = requires (T t) { std::ranges::iter_move(t); }; int main(int, char**) { + static_assert(check_iter_move()); check_iter_move(); diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp rename from libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap.pass.cpp rename to libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp --- a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp @@ -17,12 +17,14 @@ #include #include -#include "./unqualified_lookup_wrapper.h" +#include "../unqualified_lookup_wrapper.h" +#include "test_cpo.h" #include "test_iterators.h" using IterSwapT = decltype(std::ranges::iter_swap); -static_assert(std::semiregular>); +int globalBuff [2]; +static_assert(test_cpo(std::ranges::iter_swap, globalBuff + 0, globalBuff + 1)); struct HasIterSwap { int &value_; diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp --- a/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp +++ b/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp @@ -22,6 +22,7 @@ #include #include +#include "test_cpo.h" #include "test_macros.h" template @@ -251,5 +252,7 @@ static_assert(test_1_3()); static_assert(test_1_4()); + static_assert(test_cpo(std::partial_order, 1, 2)); + return 0; } diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp --- a/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp +++ b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp @@ -22,6 +22,7 @@ #include #include +#include "test_cpo.h" #include "test_macros.h" #if defined(__i386__) @@ -463,5 +464,7 @@ // static_assert(test_1_3()); // UNIMPLEMENTED static_assert(test_1_4()); + static_assert(test_cpo(std::strong_order, 1, 2)); + return 0; } diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp --- a/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp +++ b/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp @@ -22,6 +22,7 @@ #include #include +#include "test_cpo.h" #include "test_macros.h" template @@ -510,5 +511,7 @@ static_assert(test_1_4()); static_assert(test_1_5()); + static_assert(test_cpo(std::weak_order, 1, 2)); + return 0; } 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 --- 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 @@ -15,8 +15,10 @@ #include #include -#include "test_macros.h" + +#include "test_cpo.h" #include "test_iterators.h" +#include "test_macros.h" using RangeBeginT = decltype(std::ranges::begin)&; using RangeCBeginT = decltype(std::ranges::cbegin)&; @@ -30,6 +32,9 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +static_assert(test_cpo(std::ranges::begin, globalBuff)); +static_assert(test_cpo(std::ranges::cbegin, globalBuff)); + struct BeginMember { int x; constexpr const int *begin() const { return &x; } @@ -271,7 +276,6 @@ static_assert(noexcept(std::ranges::begin(brar))); static_assert(noexcept(std::ranges::cbegin(brar))); - int main(int, char**) { testArray(); static_assert(testArray()); 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 --- 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 @@ -15,8 +15,10 @@ #include #include -#include "test_macros.h" + +#include "test_cpo.h" #include "test_iterators.h" +#include "test_macros.h" using RangeEndT = decltype(std::ranges::end)&; using RangeCEndT = decltype(std::ranges::cend)&; @@ -28,6 +30,9 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +static_assert(test_cpo(std::ranges::end, globalBuff)); +static_assert(test_cpo(std::ranges::cend, globalBuff)); + struct EndMember { int x; constexpr const int *begin() const { return nullptr; } @@ -305,7 +310,6 @@ static_assert(noexcept(std::ranges::end(brar))); static_assert(noexcept(std::ranges::cend(brar))); - int main(int, char**) { testArray(); static_assert(testArray()); diff --git a/libcxx/test/std/ranges/range.access/range.prim/data.pass.cpp b/libcxx/test/std/ranges/range.access/range.prim/data.pass.cpp --- a/libcxx/test/std/ranges/range.access/range.prim/data.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.prim/data.pass.cpp @@ -15,8 +15,10 @@ #include #include -#include "test_macros.h" + +#include "test_cpo.h" #include "test_iterators.h" +#include "test_macros.h" using RangeDataT = decltype(std::ranges::data); @@ -31,6 +33,8 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +static_assert(test_cpo(std::ranges::data, globalBuff)); + struct DataMember { int x; constexpr const int *data() const { return &x; } 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 --- a/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp @@ -15,8 +15,10 @@ #include #include -#include "test_macros.h" + +#include "test_cpo.h" #include "test_iterators.h" +#include "test_macros.h" using RangeEmptyT = decltype(std::ranges::empty); using RangeSizeT = decltype(std::ranges::size); @@ -30,6 +32,9 @@ static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); +int globalBuff[2]; +static_assert(test_cpo(std::ranges::empty, globalBuff)); + 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 --- a/libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp @@ -15,8 +15,10 @@ #include #include -#include "test_macros.h" + +#include "test_cpo.h" #include "test_iterators.h" +#include "test_macros.h" using RangeSizeT = decltype(std::ranges::size); @@ -25,7 +27,8 @@ static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); -static_assert(std::semiregular>); +int globalBuff[2]; +static_assert(test_cpo(std::ranges::size, globalBuff)); struct SizeMember { constexpr size_t size() { return 42; } diff --git a/libcxx/test/std/ranges/range.access/range.prim/ssize.pass.cpp b/libcxx/test/std/ranges/range.access/range.prim/ssize.pass.cpp --- a/libcxx/test/std/ranges/range.access/range.prim/ssize.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.prim/ssize.pass.cpp @@ -15,8 +15,10 @@ #include #include -#include "test_macros.h" + +#include "test_cpo.h" #include "test_iterators.h" +#include "test_macros.h" using RangeSSizeT = decltype(std::ranges::ssize); @@ -25,7 +27,8 @@ static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); -static_assert(std::semiregular>); +int globalBuff[2]; +static_assert(test_cpo(std::ranges::ssize, globalBuff)); struct SizeMember { constexpr size_t size() { return 42; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp @@ -19,8 +19,9 @@ #include #include -#include "test_macros.h" +#include "test_cpo.h" #include "test_iterators.h" +#include "test_macros.h" int globalBuff[8]; @@ -188,6 +189,9 @@ { static_assert(std::same_as); } + { + static_assert(test_cpo(std::views::all, globalBuff)); + } return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/adaptor.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.common.view/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/adaptor.pass.cpp @@ -19,6 +19,7 @@ #include #include +#include "test_cpo.h" #include "test_iterators.h" #include "types.h" @@ -105,6 +106,10 @@ static_assert(std::same_as); } + { + static_assert(test_cpo(std::views::common, buf)); + } + return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp @@ -20,8 +20,9 @@ #include #include -#include "test_macros.h" +#include "test_cpo.h" #include "test_iterators.h" +#include "test_macros.h" struct RvalueConvertible { RvalueConvertible(const RvalueConvertible&) = delete; @@ -48,8 +49,7 @@ { static_assert(std::addressof(std::views::counted) == std::addressof(std::ranges::views::counted)); - auto copy = std::views::counted; - static_assert(std::semiregular); + static_assert(test_cpo(std::views::counted, buffer, 8)); static_assert( CountedInvocable); static_assert(!CountedInvocable); diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/adaptor.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.reverse/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/adaptor.pass.cpp @@ -19,6 +19,7 @@ #include #include +#include "test_cpo.h" #include "types.h" template @@ -169,6 +170,9 @@ { static_assert(std::same_as); } + { + static_assert(test_cpo(std::views::reverse, buf)); + } return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp @@ -19,6 +19,7 @@ #include #include +#include "test_cpo.h" #include "test_macros.h" #include "types.h" @@ -139,6 +140,9 @@ { static_assert(std::is_same_v); } + { + static_assert(test_cpo(std::views::transform, buff, [](int x){ return x + 1; })); + } return true; } diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp --- a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp @@ -16,6 +16,7 @@ #include #include +#include "test_cpo.h" #include "test_macros.h" #include "types.h" @@ -74,6 +75,10 @@ { static_assert(std::same_as); } + { + static_assert(test_cpo(std::views::iota, 1)); + static_assert(test_cpo(std::views::iota, 1, 10)); + } return true; } diff --git a/libcxx/test/support/test_cpo.h b/libcxx/test/support/test_cpo.h new file mode 100644 --- /dev/null +++ b/libcxx/test/support/test_cpo.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef SUPPORT_TEST_CPO_H +#define SUPPORT_TEST_CPO_H + +#include +#include + +// Test for basic properties of C++20 16.3.3.3.6 [customization.point.object]. +template +constexpr bool test_cpo(CPO& o, Args&&...) { + static_assert(std::is_class_v); + static_assert(std::is_trivial_v); + + auto p = o; + using T = decltype(p); + + // The type of a customization point object, ignoring cv-qualifiers, shall model semiregular. + static_assert(std::semiregular); + + // The type T of a customization point object, ignoring cv-qualifiers, shall model... + static_assert(std::invocable); + static_assert(std::invocable); + static_assert(std::invocable); + static_assert(std::invocable); + + return true; +} + +#endif // SUPPORT_TEST_CPO_H