diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 56e1468b4ca1a3f..80547c5c1f3f57e 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -100,7 +100,7 @@ "`P2396R1 `__","LWG", "Concurrency TS 2 fixes ", "November 2022","","","|concurrency TS|" "`P2505R5 `__","LWG", "Monadic Functions for ``std::expected``", "November 2022","|Complete|","17.0","" "`P2539R4 `__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","|Complete|","18.0","|format|" -"`P2602R2 `__","LWG", "Poison Pills are Too Toxic", "November 2022","","","|ranges|" +"`P2602R2 `__","LWG", "Poison Pills are Too Toxic", "November 2022","|Complete|","19.0","|ranges|" "`P2708R1 `__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","","" "","","","","","","" "`P0290R4 `__","LWG", "``apply()`` for ``synchronized_value``","February 2023","","","|concurrency TS|" diff --git a/libcxx/include/__compare/partial_order.h b/libcxx/include/__compare/partial_order.h index f3ed4900fbff252..1d2fae63e5f248b 100644 --- a/libcxx/include/__compare/partial_order.h +++ b/libcxx/include/__compare/partial_order.h @@ -28,6 +28,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD // [cmp.alg] namespace __partial_order { +void partial_order() = delete; + struct __fn { // NOLINTBEGIN(libcpp-robust-against-adl) partial_order should use ADL, but only here template diff --git a/libcxx/include/__compare/strong_order.h b/libcxx/include/__compare/strong_order.h index 3dc819e642515c5..8c363b563822218 100644 --- a/libcxx/include/__compare/strong_order.h +++ b/libcxx/include/__compare/strong_order.h @@ -37,6 +37,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD // [cmp.alg] namespace __strong_order { +void strong_order() = delete; + struct __fn { // NOLINTBEGIN(libcpp-robust-against-adl) strong_order should use ADL, but only here template diff --git a/libcxx/include/__compare/weak_order.h b/libcxx/include/__compare/weak_order.h index b82a708c29a146c..1a3e85feb233b33 100644 --- a/libcxx/include/__compare/weak_order.h +++ b/libcxx/include/__compare/weak_order.h @@ -30,6 +30,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD // [cmp.alg] namespace __weak_order { +void weak_order() = delete; + struct __fn { // NOLINTBEGIN(libcpp-robust-against-adl) weak_order should use ADL, but only here template diff --git a/libcxx/include/__iterator/iter_move.h b/libcxx/include/__iterator/iter_move.h index 202b94cccc5ac65..ba8aed3c0ffbbdc 100644 --- a/libcxx/include/__iterator/iter_move.h +++ b/libcxx/include/__iterator/iter_move.h @@ -35,7 +35,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace ranges { namespace __iter_move { -void iter_move(); +void iter_move() = delete; template concept __unqualified_iter_move = __class_or_enum> && requires(_Tp&& __t) { diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h index 263fdd637fd965a..218b3928ecdc5f3 100644 --- a/libcxx/include/__ranges/access.h +++ b/libcxx/include/__ranges/access.h @@ -45,8 +45,7 @@ concept __member_begin = __can_borrow<_Tp> && __workaround_52970<_Tp> && require { _LIBCPP_AUTO_CAST(__t.begin()) } -> input_or_output_iterator; }; -void begin(auto&) = delete; -void begin(const auto&) = delete; +void begin() = delete; template concept __unqualified_begin = @@ -109,8 +108,7 @@ concept __member_end = __can_borrow<_Tp> && __workaround_52970<_Tp> && requires( { _LIBCPP_AUTO_CAST(__t.end()) } -> sentinel_for>; }; -void end(auto&) = delete; -void end(const auto&) = delete; +void end() = delete; template concept __unqualified_end = diff --git a/libcxx/include/__ranges/rbegin.h b/libcxx/include/__ranges/rbegin.h index 7111201ae7d6bb8..947e428f00cd52c 100644 --- a/libcxx/include/__ranges/rbegin.h +++ b/libcxx/include/__ranges/rbegin.h @@ -40,8 +40,7 @@ concept __member_rbegin = __can_borrow<_Tp> && __workaround_52970<_Tp> && requir { _LIBCPP_AUTO_CAST(__t.rbegin()) } -> input_or_output_iterator; }; -void rbegin(auto&) = delete; -void rbegin(const auto&) = delete; +void rbegin() = delete; template concept __unqualified_rbegin = diff --git a/libcxx/include/__ranges/rend.h b/libcxx/include/__ranges/rend.h index 58d98aafd264b83..1b6be58fea24b47 100644 --- a/libcxx/include/__ranges/rend.h +++ b/libcxx/include/__ranges/rend.h @@ -42,8 +42,7 @@ concept __member_rend = __can_borrow<_Tp> && __workaround_52970<_Tp> && requires { _LIBCPP_AUTO_CAST(__t.rend()) } -> sentinel_for; }; -void rend(auto&) = delete; -void rend(const auto&) = delete; +void rend() = delete; template concept __unqualified_rend = diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h index 14e21aae6bf1d56..59ca2b11ee38907 100644 --- a/libcxx/include/__ranges/size.h +++ b/libcxx/include/__ranges/size.h @@ -41,8 +41,7 @@ inline constexpr bool disable_sized_range = false; namespace ranges { namespace __size { -void size(auto&) = delete; -void size(const auto&) = delete; +void size() = delete; template concept __size_enabled = !disable_sized_range>; diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp index dd78707f25409c4..e6507f7e7767351 100644 --- a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp @@ -47,6 +47,13 @@ static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +struct StructWithNotMoreSpecializedIterSwap { + friend void iter_swap(auto&, auto&); +}; + +static_assert( + !std::is_invocable_v); + struct NodiscardIterSwap { [[nodiscard]] friend int iter_swap(NodiscardIterSwap&, NodiscardIterSwap&) { return 0; } }; diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp index ca25fc297a01191..5ca3d59abb1407f 100644 --- a/libcxx/test/std/ranges/range.access/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp @@ -192,7 +192,7 @@ struct BeginFunction { }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); @@ -245,7 +245,7 @@ struct BeginFunctionWithPrivateBeginMember { constexpr bool testBeginFunction() { BeginFunction a{}; const BeginFunction aa{}; - static_assert(!std::invocable); + assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cbegin(a) == &a.x); assert(std::ranges::begin(aa) == &aa.x); assert(std::ranges::cbegin(aa) == &aa.x); @@ -266,21 +266,21 @@ constexpr bool testBeginFunction() { BeginFunctionReturnsEmptyPtr d{}; const BeginFunctionReturnsEmptyPtr dd{}; - static_assert(!std::invocable); + assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cbegin(d) == &d.x); assert(std::ranges::begin(dd) == &dd.x); assert(std::ranges::cbegin(dd) == &dd.x); BeginFunctionWithDataMember e{}; const BeginFunctionWithDataMember ee{}; - static_assert(!std::invocable); + assert(std::ranges::begin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::begin(ee) == &ee.x); assert(std::ranges::cbegin(e) == &e.x); assert(std::ranges::cbegin(ee) == &ee.x); BeginFunctionWithPrivateBeginMember f{}; const BeginFunctionWithPrivateBeginMember ff{}; - static_assert(!std::invocable); + assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cbegin(f) == &f.y); assert(std::ranges::begin(ff) == &ff.y); assert(std::ranges::cbegin(ff) == &ff.y); diff --git a/libcxx/test/std/ranges/range.access/end.pass.cpp b/libcxx/test/std/ranges/range.access/end.pass.cpp index 21d97354ef08d08..3e465b357e98513 100644 --- a/libcxx/test/std/ranges/range.access/end.pass.cpp +++ b/libcxx/test/std/ranges/range.access/end.pass.cpp @@ -193,7 +193,7 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); @@ -271,7 +271,7 @@ constexpr bool testEndFunction() { assert(std::ranges::end(a) == &a.x); assert(std::ranges::cend(a) == &a.x); EndFunction aa{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cend(aa) == &aa.x); EndFunctionByValue b; @@ -286,28 +286,28 @@ constexpr bool testEndFunction() { assert(std::ranges::end(d) == &d.x); assert(std::ranges::cend(d) == &d.x); EndFunctionReturnsEmptyPtr dd{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cend(dd) == &dd.x); const EndFunctionWithDataMember e{}; assert(std::ranges::end(e) == &e.x); assert(std::ranges::cend(e) == &e.x); EndFunctionWithDataMember ee{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cend(ee) == &ee.x); const EndFunctionWithPrivateEndMember f{}; assert(std::ranges::end(f) == &f.y); assert(std::ranges::cend(f) == &f.y); EndFunctionWithPrivateEndMember ff{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cend(ff) == &ff.y); const BeginMemberEndFunction g{}; assert(std::ranges::end(g) == &g.x); assert(std::ranges::cend(g) == &g.x); BeginMemberEndFunction gg{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::end(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cend(gg) == &gg.x); return true; diff --git a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp index e1a564c94ed9488..3997f38efd0298c 100644 --- a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp +++ b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp @@ -187,7 +187,8 @@ struct RBeginFunction { }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); +static_assert( + std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); @@ -246,7 +247,7 @@ struct RBeginFunctionWithPrivateBeginMember { constexpr bool testRBeginFunction() { RBeginFunction a{}; const RBeginFunction aa{}; - static_assert(!std::invocable); + assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crbegin(a) == &a.x); assert(std::ranges::rbegin(aa) == &aa.x); assert(std::ranges::crbegin(aa) == &aa.x); @@ -267,21 +268,21 @@ constexpr bool testRBeginFunction() { RBeginFunctionReturnsEmptyPtr d{}; const RBeginFunctionReturnsEmptyPtr dd{}; - static_assert(!std::invocable); + assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crbegin(d) == &d.x); assert(std::ranges::rbegin(dd) == &dd.x); assert(std::ranges::crbegin(dd) == &dd.x); RBeginFunctionWithDataMember e{}; const RBeginFunctionWithDataMember ee{}; - static_assert(!std::invocable); + assert(std::ranges::rbegin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::rbegin(ee) == &ee.x); assert(std::ranges::crbegin(e) == &e.x); assert(std::ranges::crbegin(ee) == &ee.x); RBeginFunctionWithPrivateBeginMember f{}; const RBeginFunctionWithPrivateBeginMember ff{}; - static_assert(!std::invocable); + assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crbegin(f) == &f.y); assert(std::ranges::rbegin(ff) == &ff.y); assert(std::ranges::crbegin(ff) == &ff.y); diff --git a/libcxx/test/std/ranges/range.access/rend.pass.cpp b/libcxx/test/std/ranges/range.access/rend.pass.cpp index 5ba244b6b18cfec..f5f59edf19393fb 100644 --- a/libcxx/test/std/ranges/range.access/rend.pass.cpp +++ b/libcxx/test/std/ranges/range.access/rend.pass.cpp @@ -196,7 +196,7 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); @@ -272,7 +272,7 @@ constexpr bool testREndFunction() { assert(std::ranges::rend(a) == &a.x); assert(std::ranges::crend(a) == &a.x); REndFunction aa{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::rend(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crend(aa) == &aa.x); REndFunctionByValue b; @@ -287,28 +287,28 @@ constexpr bool testREndFunction() { assert(std::ranges::rend(d) == &d.x); assert(std::ranges::crend(d) == &d.x); REndFunctionReturnsEmptyPtr dd{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::rend(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crend(dd) == &dd.x); const REndFunctionWithDataMember e{}; assert(std::ranges::rend(e) == &e.x); assert(std::ranges::crend(e) == &e.x); REndFunctionWithDataMember ee{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::rend(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crend(ee) == &ee.x); const REndFunctionWithPrivateEndMember f{}; assert(std::ranges::rend(f) == &f.y); assert(std::ranges::crend(f) == &f.y); REndFunctionWithPrivateEndMember ff{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::rend(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crend(ff) == &ff.y); const RBeginMemberEndFunction g{}; assert(std::ranges::rend(g) == &g.x); assert(std::ranges::crend(g) == &g.x); RBeginMemberEndFunction gg{}; - static_assert(!std::is_invocable_v); + assert(std::ranges::rend(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::crend(gg) == &gg.x); return true; diff --git a/libcxx/test/std/ranges/range.access/size.pass.cpp b/libcxx/test/std/ranges/range.access/size.pass.cpp index fd7d0a8b9975225..ee44aa815ba993b 100644 --- a/libcxx/test/std/ranges/range.access/size.pass.cpp +++ b/libcxx/test/std/ranges/range.access/size.pass.cpp @@ -219,7 +219,8 @@ inline constexpr bool std::ranges::disable_sized_range); static_assert( std::is_invocable_v); -static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic static_assert( std::is_invocable_v); // No begin end. diff --git a/libcxx/test/std/ranges/robust_against_poison_pills.compile.pass.cpp b/libcxx/test/std/ranges/robust_against_poison_pills.compile.pass.cpp new file mode 100644 index 000000000000000..1b3da814d080027 --- /dev/null +++ b/libcxx/test/std/ranges/robust_against_poison_pills.compile.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// , , + +// ADL should be performed. Ordinary unqualified lookup should not be performed. + +namespace ns { +struct StructWithGlobalFunctions {}; +} // namespace ns + +struct ConvertibleToCmpType; +ConvertibleToCmpType strong_order(const ns::StructWithGlobalFunctions&, const ns::StructWithGlobalFunctions&); +ConvertibleToCmpType weak_order(const ns::StructWithGlobalFunctions&, const ns::StructWithGlobalFunctions&); +ConvertibleToCmpType partial_order(const ns::StructWithGlobalFunctions&, const ns::StructWithGlobalFunctions&); + +int&& iter_move(const ns::StructWithGlobalFunctions&); +void iter_swap(const ns::StructWithGlobalFunctions&, const ns::StructWithGlobalFunctions&); + +int* begin(const ns::StructWithGlobalFunctions&); +int* end(const ns::StructWithGlobalFunctions&); +int* rbegin(const ns::StructWithGlobalFunctions&); +int* rend(const ns::StructWithGlobalFunctions&); +unsigned int size(const ns::StructWithGlobalFunctions&); + +#include +#include +#include + +struct ConvertibleToCmpType { + operator std::strong_ordering() const; + operator std::weak_ordering() const; + operator std::partial_ordering() const; +}; + +struct StructWithHiddenFriends { + friend ConvertibleToCmpType strong_order(const StructWithHiddenFriends&, const StructWithHiddenFriends&); + friend ConvertibleToCmpType weak_order(const StructWithHiddenFriends&, const StructWithHiddenFriends&); + friend ConvertibleToCmpType partial_order(const StructWithHiddenFriends&, const StructWithHiddenFriends&); + + friend int&& iter_move(const StructWithHiddenFriends&); + friend void iter_swap(const StructWithHiddenFriends&, const StructWithHiddenFriends&); + + friend int* begin(const StructWithHiddenFriends&); + friend int* end(const StructWithHiddenFriends&); + friend int* rbegin(const StructWithHiddenFriends&); + friend int* rend(const StructWithHiddenFriends&); + friend unsigned int size(const StructWithHiddenFriends&); +}; + +// [cmp.alg] ADL should be performed. +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); + +// [cmp.alg] Ordinary unqualified lookup should not be performed. +static_assert( + !std::is_invocable_v); +static_assert( + !std::is_invocable_v); +static_assert( + !std::is_invocable_v); + +// [iterator.cust] ADL should be performed. +static_assert(std::is_invocable_v); +static_assert( + std::is_invocable_v); + +// [iterator.cust] Ordinary unqualified lookup should not be performed. +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +// [range.access] ADL should be performed. +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); + +// [range.access] Ordinary unqualified lookup should not be performed. +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v);