diff --git a/libcxx/include/concepts b/libcxx/include/concepts --- a/libcxx/include/concepts +++ b/libcxx/include/concepts @@ -218,6 +218,15 @@ constructible_from<_Tp, const _Tp&> && convertible_to && constructible_from<_Tp, const _Tp> && convertible_to; +// [concept.booleantestable] +template +concept __boolean_testable_impl = convertible_to<_Tp, bool>; + +template +concept __boolean_testable = __boolean_testable_impl<_Tp> && requires(_Tp&& __t) { + { !std::forward<_Tp>(__t) } -> __boolean_testable_impl; +}; + // [concept.invocable] template concept invocable = requires(_Fn&& __fn, _Args&&... __args) { @@ -228,7 +237,25 @@ template concept regular_invocable = invocable<_Fn, _Args...>; -#endif // _LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L +// [concept.predicate] +template +concept predicate = + regular_invocable<_Fn, _Args...> && __boolean_testable>; + +// [concept.relation] +template +concept relation = + predicate<_Rp, _Tp, _Tp> && predicate<_Rp, _Up, _Up> && + predicate<_Rp, _Tp, _Up> && predicate<_Rp, _Up, _Tp>; + +// [concept.equiv] +template +concept equivalence_relation = relation<_Rp, _Tp, _Up>; + +// [concept.strictweakorder] +template +concept strict_weak_order = relation<_Rp, _Tp, _Up>; +#endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/concepts/callable/equiv.compile.pass.cpp b/libcxx/test/std/concepts/callable/equiv.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/concepts/callable/equiv.compile.pass.cpp @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept equivalence_relation; + +#include +#include +#include +#include +#include + +#include "functions.h" + +template +requires std::equivalence_relation constexpr void +ModelsEquivalenceRelation(F, T&&, U&&) noexcept {} + +template +requires(!std::equivalence_relation) constexpr + void NotEquivalenceRelation(F, T&&, U&&) noexcept {} + +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); +static_assert(!std::equivalence_relation); + +int main(int, char**) { + // The difference between `std::relation` and `std::equivalence_relation` is + // purely semantic. Tests that are commented out with /// satisfy + // `std::equivalence_relation`, but don't model the semantic requirements. + // They're kept here for informational purposes only. + { + using RegularInvocable::A; + NotEquivalenceRelation(&A::F, 0, 0); + NotEquivalenceRelation(&A::G, 0, 0); + NotEquivalenceRelation(RegularInvocable::F, 0, 0); + NotEquivalenceRelation(RegularInvocable::G, 0, 0); + + { + auto Up = std::make_unique(); + NotEquivalenceRelation(&A::I, Up, 0); + NotEquivalenceRelation(&A::F, Up, 0); + NotEquivalenceRelation(&A::G, Up, 0); + NotEquivalenceRelation(&A::H, Up, 0); + } + { + auto Sp = std::make_shared(); + NotEquivalenceRelation(&A::I, Sp, 0); + NotEquivalenceRelation(&A::F, Sp, 0); + NotEquivalenceRelation(&A::G, Sp, 0); + NotEquivalenceRelation(&A::H, Sp, 0); + } + { + A X; + auto Rw = std::reference_wrapper(X); + NotEquivalenceRelation(&A::I, Rw, 0); + NotEquivalenceRelation(&A::F, Rw, 0); + NotEquivalenceRelation(&A::G, Rw, 0); + NotEquivalenceRelation(&A::H, Rw, 0); + } + } + + { + NotEquivalenceRelation(Predicate::L2rSorted(), 0, 0.0); + NotEquivalenceRelation(Predicate::NotAPredicate(), 0, 0); + ModelsEquivalenceRelation(Predicate::LambdaPredicate, 0, 1.0); + } + { + ModelsEquivalenceRelation(Relation::EqualTo, 0, 0); + /// ModelsEquivalenceRelation(Relation::Greater, 0, 0); + /// ModelsEquivalenceRelation(Relation::Greater, 0.0, 0); + ModelsEquivalenceRelation(Relation::MaybeRelation(), 0, 0); + ModelsEquivalenceRelation(Relation::MaybeRelation(), 0, 0.0); + ModelsEquivalenceRelation(Relation::MaybeRelation(), 0.0, 0); + NotEquivalenceRelation(Relation::MaybeRelation(), 0, + Predicate::LambdaPredicate); + NotEquivalenceRelation(Relation::MaybeRelation(), + Predicate::LambdaPredicate, 0); + + ModelsEquivalenceRelation(Relation::Equivalent(), 0, 10L); + ModelsEquivalenceRelation(Relation::Equivalent(), 0, 1.0L); + /// ModelsEquivalenceRelation(Relation::Less(), 0, 10L); + /// ModelsEquivalenceRelation(Relation::Less(), 0, 1.0L); + + const Relation::MaybeRelation StillARelation; + ModelsEquivalenceRelation(StillARelation, 0, 0); + } + return 0; +} diff --git a/libcxx/test/std/concepts/callable/functions.h b/libcxx/test/std/concepts/callable/functions.h --- a/libcxx/test/std/concepts/callable/functions.h +++ b/libcxx/test/std/concepts/callable/functions.h @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -#ifndef CALLABLE_FUNCTIONS_H -#define CALLABLE_FUNCTIONS_H +#ifndef TEST_STD_CONCEPTS_CALLABLE_FUNCTIONS_H +#define TEST_STD_CONCEPTS_CALLABLE_FUNCTIONS_H namespace RegularInvocable { struct A { @@ -20,6 +20,10 @@ constexpr int G(int I) { return 2 * I + 1; } } // namespace RegularInvocable +struct Bool { + int Value = false; + constexpr operator bool() const noexcept { return Value; } +}; namespace Predicate { struct L2rSorted { template @@ -28,13 +32,34 @@ } }; +struct L2rSortedWithBooleanTestable { + constexpr Bool AlwaysTrue() const noexcept { return Bool(); } +}; struct NotAPredicate { void operator()() const noexcept {} + void operator()(int, int) const noexcept {} }; + +inline constexpr auto LambdaPredicate = [](int, double) { return true; }; +inline constexpr auto ReturnsConvertibleToBool = [] { return LambdaPredicate; }; +inline constexpr auto ReturnsNotAPredicate = [] { return NotAPredicate(); }; } // namespace Predicate namespace Relation { -int Greater(int X, int Y) noexcept { return X > Y; } +constexpr double EqualTo(long long X, long long Y) noexcept { return X == Y; } +constexpr int Greater(int X, int Y) noexcept { return X > Y; } + +struct MaybeRelation { + Bool operator()(int, auto) { return {}; } +}; + +struct Equivalent { + Bool operator()(int X, long Y) const noexcept { return {X == Y}; } +}; + +struct Less { + bool operator()(int X, long Y) const noexcept { return X < Y; } +}; } // namespace Relation -#endif // CALLABLE_FUNCTIONS_H +#endif // TEST_STD_CONCEPTS_CALLABLE_FUNCTIONS_H diff --git a/libcxx/test/std/concepts/callable/invocable.compile.pass.cpp b/libcxx/test/std/concepts/callable/invocable.compile.pass.cpp --- a/libcxx/test/std/concepts/callable/invocable.compile.pass.cpp +++ b/libcxx/test/std/concepts/callable/invocable.compile.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-no-concepts -// template +// template // concept invocable; #include @@ -83,6 +83,14 @@ ModelsInvocable(&A::G, Sp, 0); NotInvocable(&A::H, Sp, 0); } + { + A X; + auto Rw = std::reference_wrapper(X); + ModelsInvocable(&A::I, Rw); + ModelsInvocable(&A::F, Rw); + ModelsInvocable(&A::G, Rw, 0); + NotInvocable(&A::H, Rw, 0); + } } { using namespace Predicate; @@ -106,6 +114,18 @@ NotInvocable(&L2rSorted::operator(), Sp, 0); NotInvocable(&L2rSorted::operator(), Sp, 0, 1); } + { + L2rSorted X; + auto Rw = std::reference_wrapper(X); + ModelsInvocable(&L2rSorted::operator(), Rw, 0, 1, 2); + NotInvocable(&L2rSorted::operator(), Rw, 0); + } + } + { + ModelsInvocable(Relation::Greater, 0, 0); + ModelsInvocable(Relation::Greater, 0, 0.0); + ModelsInvocable(Relation::MaybeRelation(), 0, Predicate::LambdaPredicate); + NotInvocable(Relation::MaybeRelation(), Predicate::LambdaPredicate, 0); } { auto G = std::mt19937_64( diff --git a/libcxx/test/std/concepts/callable/predicate.compile.pass.cpp b/libcxx/test/std/concepts/callable/predicate.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/concepts/callable/predicate.compile.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept predicate; + +#include +#include +#include +#include +#include + +#include "functions.h" + +template +requires std::predicate constexpr void +ModelsPredicate(F, Args&&...) noexcept {} + +template +requires(!std::predicate) constexpr + void NotPredicate(F, Args&&...) noexcept {} + +static_assert(!std::predicate); +static_assert(!std::predicate); +static_assert(!std::predicate); +static_assert(!std::predicate); +static_assert(!std::predicate); + +int main(int, char**) { + { + using RegularInvocable::A; + A X; + ModelsPredicate(&A::F, X); + ModelsPredicate(&A::G, X, 0); + + NotPredicate(&A::G, X); + NotPredicate(&A::G, 0); + NotPredicate(&A::H); + { + auto Sp = std::make_shared(); + ModelsPredicate(&A::I, Sp); + ModelsPredicate(&A::F, Sp); + ModelsPredicate(&A::G, Sp, 0); + NotPredicate(&A::H, Sp, 0); + } + } + { + using Predicate::L2rSorted; + L2rSorted Pred; + ModelsPredicate(Pred, 0, 0, 0); + NotPredicate(Pred, 0); + NotPredicate(Pred, 0, 1); + + using Predicate::NotAPredicate; + NotPredicate(NotAPredicate()); + + using Predicate::L2rSortedWithBooleanTestable; + L2rSortedWithBooleanTestable L2rBT; + ModelsPredicate(&L2rSortedWithBooleanTestable::AlwaysTrue, L2rBT); + + ModelsPredicate(Predicate::LambdaPredicate, 42, -0.0); + ModelsPredicate(Predicate::ReturnsConvertibleToBool); + NotPredicate(Predicate::ReturnsConvertibleToBool, -42); + NotPredicate(Predicate::ReturnsNotAPredicate); + + { + auto Up = std::make_unique(); + ModelsPredicate(&L2rSortedWithBooleanTestable::AlwaysTrue, Up); + NotPredicate(&L2rSortedWithBooleanTestable::AlwaysTrue, Up, 0); + } + { + auto Rw = std::reference_wrapper(Pred); + ModelsPredicate(&L2rSorted::operator(), Rw, 0, 1, 2); + NotPredicate(&L2rSorted::operator(), Rw); + NotPredicate(&L2rSorted::operator(), Rw, 0); + NotPredicate(&L2rSorted::operator(), Rw, 0, 1); + } + } + + ModelsPredicate(Relation::Greater, 0, 0); + ModelsPredicate(Relation::Greater, 0, 0.0); + ModelsPredicate(Relation::MaybeRelation(), 0, Predicate::LambdaPredicate); + NotPredicate(Relation::MaybeRelation(), Predicate::LambdaPredicate, 0); + return 0; +} diff --git a/libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp b/libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp --- a/libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp +++ b/libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-no-concepts -// template +// template // concept regular_invocable; #include @@ -82,6 +82,14 @@ ModelsRegularInvocable(&A::G, Sp, 0); NotRegularInvocable(&A::H, Sp, 0); } + { + A X; + auto Rw = std::reference_wrapper(X); + ModelsRegularInvocable(&A::I, Rw); + ModelsRegularInvocable(&A::F, Rw); + ModelsRegularInvocable(&A::G, Rw, 0); + NotRegularInvocable(&A::H, Rw, 0); + } } { using namespace Predicate; @@ -105,6 +113,20 @@ NotRegularInvocable(&L2rSorted::operator(), Sp, 0); NotRegularInvocable(&L2rSorted::operator(), Sp, 0, 1); } + { + L2rSorted X; + auto Rw = std::reference_wrapper(X); + ModelsRegularInvocable(&L2rSorted::operator(), Rw, 0, 1, 2); + NotRegularInvocable(&L2rSorted::operator(), Rw, 0); + } + } + { + ModelsRegularInvocable(Relation::Greater, 0, 0); + ModelsRegularInvocable(Relation::Greater, 0, 0.0); + ModelsRegularInvocable(Relation::MaybeRelation(), 0, + Predicate::LambdaPredicate); + NotRegularInvocable(Relation::MaybeRelation(), Predicate::LambdaPredicate, + 0); } // { // RNG doesn't model regular_invocable, left here for documentation diff --git a/libcxx/test/std/concepts/callable/relation.compile.pass.cpp b/libcxx/test/std/concepts/callable/relation.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/concepts/callable/relation.compile.pass.cpp @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept relation; + +#include +#include +#include +#include +#include + +#include "functions.h" + +template +requires std::relation constexpr void ModelsRelation(F, T&&, + U&&) noexcept {} + +template +requires(!std::relation) constexpr + void NotRelation(F, T&&, U&&) noexcept {} + +static_assert(!std::relation); +static_assert(!std::relation); +static_assert(!std::relation); +static_assert(!std::relation); +static_assert(!std::relation); +static_assert(!std::relation); +static_assert(!std::relation); +static_assert(!std::relation); +static_assert(!std::relation); +static_assert(!std::relation); + +int main(int, char**) { + { + using RegularInvocable::A; + NotRelation(&A::F, 0, 0); + NotRelation(&A::G, 0, 0); + NotRelation(RegularInvocable::F, 0, 0); + NotRelation(RegularInvocable::G, 0, 0); + + { + auto Up = std::make_unique(); + NotRelation(&A::I, Up, 0); + NotRelation(&A::F, Up, 0); + NotRelation(&A::G, Up, 0); + NotRelation(&A::H, Up, 0); + } + { + auto Sp = std::make_shared(); + NotRelation(&A::I, Sp, 0); + NotRelation(&A::F, Sp, 0); + NotRelation(&A::G, Sp, 0); + NotRelation(&A::H, Sp, 0); + } + { + A X; + auto Rw = std::reference_wrapper(X); + NotRelation(&A::I, Rw, 0); + NotRelation(&A::F, Rw, 0); + NotRelation(&A::G, Rw, 0); + NotRelation(&A::H, Rw, 0); + } + } + + { + NotRelation(Predicate::L2rSorted(), 0, 0.0); + NotRelation(Predicate::NotAPredicate(), 0, 0); + ModelsRelation(Predicate::LambdaPredicate, 0, 1.0); + } + { + ModelsRelation(Relation::EqualTo, 0, 0); + ModelsRelation(Relation::Greater, 0, 0); + ModelsRelation(Relation::Greater, 0.0, 0); + ModelsRelation(Relation::MaybeRelation(), 0, 0); + ModelsRelation(Relation::MaybeRelation(), 0, 0.0); + ModelsRelation(Relation::MaybeRelation(), 0.0, 0); + NotRelation(Relation::MaybeRelation(), 0, Predicate::LambdaPredicate); + NotRelation(Relation::MaybeRelation(), Predicate::LambdaPredicate, 0); + + ModelsRelation(Relation::Equivalent(), 0, 10L); + ModelsRelation(Relation::Equivalent(), 0, 1.0L); + ModelsRelation(Relation::Less(), 0, 10L); + ModelsRelation(Relation::Less(), 0, 1.0L); + + const Relation::MaybeRelation StillARelation; + ModelsRelation(StillARelation, 0, 0); + } + return 0; +} diff --git a/libcxx/test/std/concepts/callable/strictweakorder.compile.pass.cpp b/libcxx/test/std/concepts/callable/strictweakorder.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/concepts/callable/strictweakorder.compile.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept strict_weak_order; + +#include +#include +#include +#include +#include + +#include "functions.h" + +template +requires std::strict_weak_order constexpr void +ModelsStrictWeakOrder(F, T&&, U&&) noexcept {} + +template +requires(!std::strict_weak_order) constexpr + void NotStrictWeakOrder(F, T&&, U&&) noexcept {} + +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); +static_assert(!std::strict_weak_order); + +int main(int, char**) { + // The difference between `std::relation` and `std::strict_weak_order` is + // purely semantic. Tests that are commented out with /// satisfy + // `std::strict_weak_order`, but don't model the semantic requirements. + // They're kept here for informational purposes only. + { + using RegularInvocable::A; + NotStrictWeakOrder(&A::F, 0, 0); + NotStrictWeakOrder(&A::G, 0, 0); + NotStrictWeakOrder(RegularInvocable::F, 0, 0); + NotStrictWeakOrder(RegularInvocable::G, 0, 0); + + { + auto Up = std::make_unique(); + NotStrictWeakOrder(&A::I, Up, 0); + NotStrictWeakOrder(&A::F, Up, 0); + NotStrictWeakOrder(&A::G, Up, 0); + NotStrictWeakOrder(&A::H, Up, 0); + } + { + auto Sp = std::make_shared(); + NotStrictWeakOrder(&A::I, Sp, 0); + NotStrictWeakOrder(&A::F, Sp, 0); + NotStrictWeakOrder(&A::G, Sp, 0); + NotStrictWeakOrder(&A::H, Sp, 0); + } + { + A X; + auto Rw = std::reference_wrapper(X); + NotStrictWeakOrder(&A::I, Rw, 0); + NotStrictWeakOrder(&A::F, Rw, 0); + NotStrictWeakOrder(&A::G, Rw, 0); + NotStrictWeakOrder(&A::H, Rw, 0); + } + } + + { + /// NotStrictWeakOrder(Predicate::L2rSorted(), 0, 0.0); + /// NotStrictWeakOrder(Predicate::NotAPredicate(), 0, 0); + /// ModelsStrictWeakOrder(Predicate::LambdaPredicate, 0, 1.0); + } { + /// ModelsStrictWeakOrder(Relation::EqualTo, 0, 0); + ModelsStrictWeakOrder(Relation::Greater, 0, 0); + ModelsStrictWeakOrder(Relation::Greater, 0.0, 0); + /// ModelsStrictWeakOrder(Relation::MaybeRelation(), 0, 0); + /// ModelsStrictWeakOrder(Relation::MaybeRelation(), 0, 0.0); + /// ModelsStrictWeakOrder(Relation::MaybeRelation(), 0.0, 0); + /// NotStrictWeakOrder(Relation::MaybeRelation(), 0, Predicate::LambdaPredicate); + /// NotStrictWeakOrder(Relation::MaybeRelation(), Predicate::LambdaPredicate, 0); + + /// ModelsStrictWeakOrder(Relation::Equivalent(), 0, 10L); + /// ModelsStrictWeakOrder(Relation::Equivalent(), 0, 1.0L); + ModelsStrictWeakOrder(Relation::Less(), 0, 10L); + ModelsStrictWeakOrder(Relation::Less(), 0, 1.0L); + + /// const Relation::MaybeRelation StillARelation; + /// ModelsStrictWeakOrder(StillARelation, 0, 0); + } + return 0; +} diff --git a/libcxx/test/std/concepts/lang/moveconstructible.h b/libcxx/test/std/concepts/lang/moveconstructible.h --- a/libcxx/test/std/concepts/lang/moveconstructible.h +++ b/libcxx/test/std/concepts/lang/moveconstructible.h @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -#ifndef TEST_STD_CONCEPTS_LAND_MOVECONSTRUCTIBLE_H -#define TEST_STD_CONCEPTS_LAND_MOVECONSTRUCTIBLE_H +#ifndef TEST_STD_CONCEPTS_LANG_MOVECONSTRUCTIBLE_H +#define TEST_STD_CONCEPTS_LANG_MOVECONSTRUCTIBLE_H struct HasDefaultOps {}; @@ -58,4 +58,4 @@ int&& X; }; -#endif // TEST_STD_CONCEPTS_LAND_MOVECONSTRUCTIBLE_H +#endif // TEST_STD_CONCEPTS_LANG_MOVECONSTRUCTIBLE_H