[clang] Add option -fstdlib-hardening= (PR #78763)
var-const wrote: I personally think we absolutely should strive to add the `-fhardened` flag in a future LLVM release with semantics broadly compatible with those of GCC. However, we also need a separate way to control how hardening is enabled in libc++. For one, the `-fhardened` flag doesn't support the granularity (it can't e.g. distinguish between the fast and the extensive mode in libc++), and also it's possible that a project might want to e.g. enable hardening in the library but not to set some of the compiler flags that are part of `-fhardened` (I understand it's possible to opt out, but it feels inelegant and adds more friction). That leaves us with essentially two options: a compiler flag or a "user-facing" macro. We feel a compiler flag is preferable for several closely related reasons: - for many users, passing a macro definition manually feels "hacky" or "ugly". Unfortunately, even though it seems like a small and subjective thing, it will cause a barrier for adoption. Some users would feel that they are fiddling with the internal details of the library which might change without notice (not true in this case, but it's an additional burden on documentation/etc.). Some users would feel that having to set an internal macro indicates that this is an unpolished, unfinished feature that is not ready for production. Some users are not very comfortable with C++ and some of its older ways of doing things. To all of them, a flag would be preferable even if the effects were exactly the same. - a flag can provide better diagnostics upon misuse. E.g. I would expect that if a user passes an incorrect mode name, the compiler invocation would fail immediately if a flag is being used, whereas otherwise it would be a compilation error coming from deep within the libc++ implementation, intermixed with other compilation output and potentially duplicated several times. Also, IIUC, the compiler would reject an unknown flag but I'm not sure we can catch setting an incorrect macro. - a flag is documented in a uniform way (without users having to look for libc++-specific documentation to get even a basic idea of what each mode does); - like Louis mentioned, as C++ adopts modules, macros feel increasingly outdated; - having a flag is more future-proof in case we want to extend its effects beyond the current state. Otherwise users would have to update their build configuration (switch from setting a macro to setting the flag) to get the benefits; - the fact that the flag boils down to setting a macro is an implementation detail that most users shouldn't need to worry (or know) about. In fact, we originally considered to set a feature instead (IIUC, we decided to go with the macro to make it compatible with GCC but I'm fuzzy on the details). https://github.com/llvm/llvm-project/pull/78763 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add option -fstdlib-hardening= (PR #78763)
var-const wrote: > I think that may depend on your background. For example, in the C standard > library, there's a whole pile of `WANT` macros that users are expected to > define before including a header file Thanks, this is pretty interesting, and it's true that for users coming from that world setting a macro would probably feel quite natural. However, I generally find that the conventions of the C standard library are noticeably different from the C++ standard library, and many things that are common and normal in the C world feel unusual and sometimes inelegant. In my experience, many users feel that manually setting a macro is "hacky", doubly so if that macro has an internal name. They might also feel that they're fiddling with implementation details that might change in the future -- which wouldn't be true in this case, but IMO it still creates a certain barrier for adoption, perhaps pretty minor but still not negligible. I personally think we absolutely should strive to add the `-fhardened` flag in a future LLVM release with semantics broadly compatible with those of GCC. However, we also need a separate way to control how hardening is enabled in libc++. For one, the `-fhardened` flag doesn't support the granularity (it can't e.g. distinguish between the fast and the extensive mode in libc++), and also it's possible that a project might want to e.g. enable hardening in the library but not to set some of the compiler flags that are part of `-fhardened` (I understand it's possible to opt out, but it feels inelegant and adds more friction). That leaves us with essentially two options: a compiler flag or a "user-facing" macro. We feel a compiler flag is preferable for several closely related reasons: - for many users, passing a macro definition manually feels "hacky" or "ugly". Unfortunately, even though it seems like a small and subjective thing, it will cause a barrier for adoption. Some users would feel that they are fiddling with the internal details of the library which might change without notice (not true in this case, but it's an additional burden on documentation/etc.). Some users would feel that having to set an internal macro indicates that this is an unpolished, unfinished feature that is not ready for production. Some users are not very comfortable with C++ and some of its older ways of doing things. To all of them, a flag would be preferable even if the effects were exactly the same. - a flag can provide better diagnostics upon misuse. E.g. I would expect that if a user passes an incorrect mode name, the compiler invocation would fail immediately if a flag is being used, whereas otherwise it would be a compilation error coming from deep within the libc++ implementation, intermixed with other compilation output and potentially duplicated several times. Also, IIUC, the compiler would reject an unknown flag but I'm not sure we can catch setting an incorrect macro. - a flag is documented in a uniform way (without users having to look for libc++-specific documentation to get even a basic idea of what each mode does); - like Louis mentioned, as C++ adopts modules, macros feel increasingly outdated; - having a flag is more future-proof in case we want to extend its effects beyond the current state. Otherwise users would have to update their build configuration (switch from setting a macro to setting the flag) to get the benefits; - the fact that the flag boils down to setting a macro is an implementation detail that most users shouldn't need to worry (or know) about. In fact, we originally considered to set a feature instead (IIUC, we decided to go with the macro to make it compatible with GCC but I'm fuzzy on the details). https://github.com/llvm/llvm-project/pull/78763 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add option -fstdlib-hardening= (PR #78763)
var-const wrote: > Yes, please, unless there's a strong reason not to, consider `-fhardened`. `-fhardened` also enables a few compiler flags. I think it would be better to have a separate flag that only affects the library and hopefully in the future start supporting `-fhardened` flag that would have an aligned behavior between GCC and Clang (including enabling equivalent compiler flags where possible). https://github.com/llvm/llvm-project/pull/78763 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add support for builtin_verbose_trap (PR #79230)
https://github.com/var-const approved this pull request. LGTM from the libc++ perspective, thanks a lot for working on this! https://github.com/llvm/llvm-project/pull/79230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add support for builtin_verbose_trap (PR #79230)
@@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify %s + +#if !__has_builtin(__builtin_verbose_trap) +#error +#endif + +constexpr char const* constMsg1 = "hello"; +char const* const constMsg2 = "hello"; +char const constMsg3[] = "hello"; + +template +void f(const char * arg) { + __builtin_verbose_trap("Argument_must_not_be_null"); var-const wrote: IMO it's completely reasonable to leave supporting Unicode as a potential follow-up, but I'm happy to know what currently is and isn't supported. For the string length -- maybe let's try 128 or 256 characters? There isn't any specific size that we need to test -- just want some validation that passing a string longer than a short sentence won't cause any weird effects. https://github.com/llvm/llvm-project/pull/79230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add support for builtin_verbose_trap (PR #79230)
@@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify %s + +#if !__has_builtin(__builtin_verbose_trap) +#error +#endif + +constexpr char const* constMsg1 = "hello"; +char const* const constMsg2 = "hello"; +char const constMsg3[] = "hello"; + +template +void f(const char * arg) { + __builtin_verbose_trap("Argument_must_not_be_null"); var-const wrote: +1. Can we also check: 1. A non-ASCII Unicode character? 2. A long string (is there any limitation on the string length?)? https://github.com/llvm/llvm-project/pull/79230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add support for builtin_verbose_trap (PR #79230)
@@ -346,6 +346,14 @@ class CGDebugInfo { const FieldDecl *BitFieldDecl, const llvm::DIDerivedType *BitFieldDI, llvm::ArrayRef PreviousFieldsDI, const RecordDecl *RD); + // A cache that maps artificial inlined function names used for + // __builtin_verbose_trap to subprograms. + std::map InlinedTrapFuncMap; var-const wrote: Nit: I think this header might need to include `` and ``, otherwise it appears to rely on those headers being included transitively from somewhere. (Unless of course there's some Clang convention against doing that) https://github.com/llvm/llvm-project/pull/79230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add support for builtin_verbose_trap (PR #79230)
https://github.com/var-const commented: >From the libc++ perspective, the only substantial comment I have is that >ideally we need to make sure it's possible to pass long strings with arbitrary >characters as the string parameter (or, if it's infeasible to implement, we >need to document the limitations). https://github.com/llvm/llvm-project/pull/79230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add support for builtin_verbose_trap (PR #79230)
https://github.com/var-const edited https://github.com/llvm/llvm-project/pull/79230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libcxx] [clang-tools-extra] [clang] [llvm] [libc++][hardening] Categorize assertions related to strict weak ordering (PR #77405)
@@ -283,9 +283,20 @@ // - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure // the containers have compatible allocators. // +// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments +// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the +// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g. +// a string view where only a subset of elements is possible to access). This doesn't cause an immediate issue within +// the library but is always a logic bug and is likely to cause problems within user code. +// This is somewhat of a catch-all (or fallback) category -- it covers errors triggered by user input that don't have +// a more specific category defined (which is always preferable when available). +// // - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to // be benign in our implementation. // +// - `_LIBCPP_ASSERT_INTRUSIVE` -- for assertions that perform intrusive and typically very expensive validations of var-const wrote: Went with `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- I think this captures the intention well and implies two important properties of the check (usually a heuristic and often expensive). https://github.com/llvm/llvm-project/pull/77405 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libcxx] [clang-tools-extra] [clang] [llvm] [libc++][hardening] Categorize assertions related to strict weak ordering (PR #77405)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77405 >From f6a3ba6f2fb00b17182b405312eca4e837fe8977 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 8 Jan 2024 19:09:37 -0800 Subject: [PATCH 1/2] [libc++][hardening] Categorize assertions related to strict weak ordering If a user passes a comparator that doesn't satisfy strict weak ordering (see https://eel.is/c++draft/algorithms#alg.sorting.general) to a sorting algorithm, this can produce an incorrect result or even lead to an out-of-bounds access. Unfortunately, comprehensively validating that a given comparator indeed satisfies the strict weak ordering requirement is prohibitively expensive (see https://discourse.llvm.org/t/rfc-strict-weak-ordering-checks-in-the-debug-libc/70217). As a result, we have three independent sets of checks, in order from least to most expensive: - assertions that catch out-of-bounds accesses within the algorithms' implementation. These are relatively cheap; however, they cannot catch the underlying cause and cannot prevent the case where an invalid comparator would result in an uncorrectly-sorted sequence without producing an OOB access; - debug comparators that wrap a given comparator and on each comparison check that if `(a < b)`, then `!(b < a)`, where `<` stands for the user-provided comparator. This performs up to 2x number of comparisons but doesn't affect the algorithmic complexity. While this approach can find more issues, it is still a heuristic; - a comprehensive check of the comparator that validates up to 100 elements in the resulting sorted sequence (see the RFC above for details), imposing a significant performance overhead. Accordingly, the first set of checks is enabled in the fast hardening mode, the second in the extensive mode, and the third only in the debug mode. For the most expensive checks, introduce a new category `_LIBCPP_ASSERT_INTRUSIVE`. This category is intended for expensive checks that perform intrusive, extensive validation within the implementation (either of the user input or of invariants or postconditions of a function). See https://reviews.llvm.org/D150264 for additional background. --- libcxx/include/__algorithm/comp_ref_type.h| 9 libcxx/include/__algorithm/nth_element.h | 8 +++ libcxx/include/__algorithm/sort.h | 22 +- .../__algorithm/three_way_comp_ref_type.h | 10 libcxx/include/__config | 23 +++ .../strict_weak_ordering_check.h | 10 6 files changed, 53 insertions(+), 29 deletions(-) diff --git a/libcxx/include/__algorithm/comp_ref_type.h b/libcxx/include/__algorithm/comp_ref_type.h index 15f4a535a30bf0..2583eec63eef66 100644 --- a/libcxx/include/__algorithm/comp_ref_type.h +++ b/libcxx/include/__algorithm/comp_ref_type.h @@ -44,7 +44,7 @@ struct __debug_less { _LIBCPP_CONSTEXPR_SINCE_CXX14 inline _LIBCPP_HIDE_FROM_ABI decltype((void)std::declval<_Compare&>()( std::declval<_LHS&>(), std::declval<_RHS&>())) __do_compare_assert(int, _LHS& __l, _RHS& __r) { -_LIBCPP_ASSERT_UNCATEGORIZED(!__comp_(__l, __r), "Comparator does not induce a strict weak ordering"); +_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__comp_(__l, __r), "Comparator does not induce a strict weak ordering"); (void)__l; (void)__r; } @@ -53,10 +53,9 @@ struct __debug_less { _LIBCPP_CONSTEXPR_SINCE_CXX14 inline _LIBCPP_HIDE_FROM_ABI void __do_compare_assert(long, _LHS&, _RHS&) {} }; -// Pass the comparator by lvalue reference. Or in debug mode, using a -// debugging wrapper that stores a reference. -#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG -template +// Pass the comparator by lvalue reference. Or in the extensive hardening mode and above, using a debugging wrapper that +// stores a reference. +#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_EXTENSIVE || _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG using __comp_ref_type = __debug_less<_Comp>; #else template diff --git a/libcxx/include/__algorithm/nth_element.h b/libcxx/include/__algorithm/nth_element.h index a0597051259518..37ddfbdacf044d 100644 --- a/libcxx/include/__algorithm/nth_element.h +++ b/libcxx/include/__algorithm/nth_element.h @@ -114,12 +114,12 @@ __nth_element( while (true) { while (!__comp(*__first, *__i)) { ++__i; -_LIBCPP_ASSERT_UNCATEGORIZED( +_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __i != __last, "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); } do { -_LIBCPP_ASSERT_UNCATEGORIZED( +_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __j != __first, "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); --__j; @@
[clang-tools-extra] [libc] [clang] [flang] [llvm] [libcxx] [compiler-rt] [lld] [mlir] [libc++][hardening] Don't trigger redundant checks in the fast mode. (PR #77176)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77176 >From f86839d0bfc8b2070127dc3b2c609c2b3f7239ad Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 5 Jan 2024 20:08:27 -0800 Subject: [PATCH 1/2] [libc++][hardening] Don't trigger redundant checks in the fast mode. Sometimes we essentially check the same condition twice -- for example, a class might check that an index into its vector member variable is valid before accessing it, but `vector::operator[]` contains the same check. These "redundant" checks allow catching errors closer to the source and providing a better error message, but they also impose additional overhead. Marking the "early" checks as redundant allows ignoring them in the fast mode (while still getting a guaranteed trap) while still getting better error messages in the extensive mode and above. Introducing a separate wrapper macro allows making the concept of redundant assertions orthogonal to assertion categories and retaining the actual category of a check. This is a follow-up to https://github.com/llvm/llvm-project/pull/75918, specifically to [this discussion](https://github.com/llvm/llvm-project/pull/75918#discussion_r1434493455). --- libcxx/include/__config | 16 .../include/__filesystem/directory_iterator.h | 3 ++- libcxx/include/__iterator/next.h| 5 +++-- libcxx/include/__iterator/prev.h| 5 +++-- libcxx/include/__mdspan/layout_left.h | 5 +++-- libcxx/include/__mdspan/layout_right.h | 5 +++-- libcxx/include/__mdspan/layout_stride.h | 5 +++-- libcxx/include/__ranges/chunk_by_view.h | 17 +++-- libcxx/include/__ranges/drop_while_view.h | 9 + libcxx/include/__ranges/filter_view.h | 5 +++-- libcxx/include/regex| 3 ++- 11 files changed, 54 insertions(+), 24 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 082c73e672c7492..b20e8abed0939cc 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -290,6 +290,18 @@ // user input. // // - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet. +// +// In addition to these categories, `_LIBCPP_REDUNDANT_ASSERTION` should be used to wrap assertions that duplicate other +// assertions (for example, a range view might check that its `optional` data member holds a value before dereferencing +// it, but this is already checked by `optional` itself). Redundant assertions incur an additional performance overhead +// and don't provide any extra security benefit, but catching an error earlier allows halting the program closer to the +// root cause and giving the user an error message that contains more context. Due to these tradeoffs, redundant +// assertions are disabled in the fast mode but are enabled in the extensive mode and above. Thus, going back to the +// example above, if a view attempts to dereference an empty optional member variable: +// - in the fast mode, the program will only perform one check and will trap inside the optional (with an error +// amounting to "Attempting to dereference an empty optional"); +// - in the extensive mode, the program will normally perform two checks (in the non-error case), and if the optional is +// empty, it will trap inside the view (with an error like "`foo_view` doesn't have a valid predicate"). // clang-format off # define _LIBCPP_HARDENING_MODE_NONE (1 << 1) @@ -331,6 +343,7 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_REDUNDANT_ASSERTION(expression) _LIBCPP_ASSUME(expression) // Extensive hardening mode checks. @@ -344,6 +357,7 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_REDUNDANT_ASSERTION(expression) expression // Disabled checks. #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) @@ -360,6 +374,7 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression,
[libcxx] [clang-tools-extra] [clang] [llvm] [libc++][hardening] Categorize assertions related to strict weak ordering (PR #77405)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77405 >From f6a3ba6f2fb00b17182b405312eca4e837fe8977 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 8 Jan 2024 19:09:37 -0800 Subject: [PATCH] [libc++][hardening] Categorize assertions related to strict weak ordering If a user passes a comparator that doesn't satisfy strict weak ordering (see https://eel.is/c++draft/algorithms#alg.sorting.general) to a sorting algorithm, this can produce an incorrect result or even lead to an out-of-bounds access. Unfortunately, comprehensively validating that a given comparator indeed satisfies the strict weak ordering requirement is prohibitively expensive (see https://discourse.llvm.org/t/rfc-strict-weak-ordering-checks-in-the-debug-libc/70217). As a result, we have three independent sets of checks, in order from least to most expensive: - assertions that catch out-of-bounds accesses within the algorithms' implementation. These are relatively cheap; however, they cannot catch the underlying cause and cannot prevent the case where an invalid comparator would result in an uncorrectly-sorted sequence without producing an OOB access; - debug comparators that wrap a given comparator and on each comparison check that if `(a < b)`, then `!(b < a)`, where `<` stands for the user-provided comparator. This performs up to 2x number of comparisons but doesn't affect the algorithmic complexity. While this approach can find more issues, it is still a heuristic; - a comprehensive check of the comparator that validates up to 100 elements in the resulting sorted sequence (see the RFC above for details), imposing a significant performance overhead. Accordingly, the first set of checks is enabled in the fast hardening mode, the second in the extensive mode, and the third only in the debug mode. For the most expensive checks, introduce a new category `_LIBCPP_ASSERT_INTRUSIVE`. This category is intended for expensive checks that perform intrusive, extensive validation within the implementation (either of the user input or of invariants or postconditions of a function). See https://reviews.llvm.org/D150264 for additional background. --- libcxx/include/__algorithm/comp_ref_type.h| 9 libcxx/include/__algorithm/nth_element.h | 8 +++ libcxx/include/__algorithm/sort.h | 22 +- .../__algorithm/three_way_comp_ref_type.h | 10 libcxx/include/__config | 23 +++ .../strict_weak_ordering_check.h | 10 6 files changed, 53 insertions(+), 29 deletions(-) diff --git a/libcxx/include/__algorithm/comp_ref_type.h b/libcxx/include/__algorithm/comp_ref_type.h index 15f4a535a30bf0d..2583eec63eef665 100644 --- a/libcxx/include/__algorithm/comp_ref_type.h +++ b/libcxx/include/__algorithm/comp_ref_type.h @@ -44,7 +44,7 @@ struct __debug_less { _LIBCPP_CONSTEXPR_SINCE_CXX14 inline _LIBCPP_HIDE_FROM_ABI decltype((void)std::declval<_Compare&>()( std::declval<_LHS&>(), std::declval<_RHS&>())) __do_compare_assert(int, _LHS& __l, _RHS& __r) { -_LIBCPP_ASSERT_UNCATEGORIZED(!__comp_(__l, __r), "Comparator does not induce a strict weak ordering"); +_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__comp_(__l, __r), "Comparator does not induce a strict weak ordering"); (void)__l; (void)__r; } @@ -53,10 +53,9 @@ struct __debug_less { _LIBCPP_CONSTEXPR_SINCE_CXX14 inline _LIBCPP_HIDE_FROM_ABI void __do_compare_assert(long, _LHS&, _RHS&) {} }; -// Pass the comparator by lvalue reference. Or in debug mode, using a -// debugging wrapper that stores a reference. -#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG -template +// Pass the comparator by lvalue reference. Or in the extensive hardening mode and above, using a debugging wrapper that +// stores a reference. +#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_EXTENSIVE || _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG using __comp_ref_type = __debug_less<_Comp>; #else template diff --git a/libcxx/include/__algorithm/nth_element.h b/libcxx/include/__algorithm/nth_element.h index a05970512595181..37ddfbdacf044d0 100644 --- a/libcxx/include/__algorithm/nth_element.h +++ b/libcxx/include/__algorithm/nth_element.h @@ -114,12 +114,12 @@ __nth_element( while (true) { while (!__comp(*__first, *__i)) { ++__i; -_LIBCPP_ASSERT_UNCATEGORIZED( +_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __i != __last, "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); } do { -_LIBCPP_ASSERT_UNCATEGORIZED( +_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __j != __first, "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); --__j; @@
[clang-tools-extra] [libc] [clang] [flang] [llvm] [libcxx] [compiler-rt] [lld] [mlir] [libc++][hardening] Classify assertions related to leaks and syscalls. (PR #77164)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77164 >From e28e7b3e1337cb960cdc8028a70a43740fa7d636 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 21 Dec 2023 14:36:47 -0800 Subject: [PATCH 1/4] [libc++][hardening] Classify assertions related to leaks and syscalls. Introduce two new categories: - `_LIBCPP_ASSERT_VALID_DEALLOCATION`; - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL`. --- libcxx/include/__config | 16 libcxx/include/__coroutine/coroutine_handle.h| 16 .../__memory_resource/polymorphic_allocator.h| 3 ++- libcxx/src/filesystem/operations.cpp | 8 +--- libcxx/src/memory_resource.cpp | 3 ++- libcxx/src/mutex.cpp | 8 +--- 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 082c73e672c749..4d74b564864272 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -280,6 +280,14 @@ // - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the // given ranges do not overlap. // +// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object +// was allocated by the given allocator). Violating this category typically results in a memory leak. +// +// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API (e.g. a syscall) doesn't fail in +// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like +// attempting to unlock an unlocked mutex in pthreads). We generally don't expect these failures to compromize memory +// safety or otherwise create an immediate security issue. +// // - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure // the containers have compatible allocators. // @@ -327,6 +335,8 @@ _LIBCPP_HARDENING_MODE_DEBUG // Overlapping ranges will make algorithms produce incorrect results but don't directly lead to a security // vulnerability. #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) @@ -341,6 +351,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) @@ -356,6 +368,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message) @@ -370,6 +384,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression) #
[clang-tools-extra] [libc] [clang] [flang] [llvm] [libcxx] [compiler-rt] [lld] [mlir] [libc++][hardening] Categorize assertions that produce incorrect results (PR #77183)
https://github.com/var-const closed https://github.com/llvm/llvm-project/pull/77183 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc] [clang] [flang] [llvm] [libcxx] [compiler-rt] [lld] [mlir] [libc++][hardening] Categorize assertions that produce incorrect results (PR #77183)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77183 >From 2d62194c2c30b5072c8d42bf30d3b5163b1eb844 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 5 Jan 2024 23:34:42 -0800 Subject: [PATCH 1/2] [libc++][hardening] Categorize assertions that produce incorrect results Introduce a new `argument-within-domain` category that covers cases where the given arguments make it impossible to produce a correct result (or create a valid object in case of constructors). While the incorrect result doesn't create an immediate problem within the library (like e.g. a null pointer dereference would), it always indicates a logic error in user code and is highly likely to lead to a bug in the program once the value is used. --- libcxx/include/__algorithm/clamp.h | 2 +- libcxx/include/__algorithm/ranges_clamp.h| 5 +++-- libcxx/include/__bit/bit_ceil.h | 2 +- libcxx/include/__config | 14 +- libcxx/include/__hash_table | 2 +- libcxx/include/__memory/assume_aligned.h | 3 ++- libcxx/include/__numeric/gcd_lcm.h | 2 +- libcxx/include/barrier | 12 ++-- libcxx/include/latch | 10 +- libcxx/include/semaphore | 8 libcxx/include/string_view | 7 +-- libcxx/src/filesystem/operations.cpp | 5 ++--- libcxx/src/include/to_chars_floating_point.h | 2 +- 13 files changed, 45 insertions(+), 29 deletions(-) diff --git a/libcxx/include/__algorithm/clamp.h b/libcxx/include/__algorithm/clamp.h index 1631b2673c3faf..003bf70dd4f01d 100644 --- a/libcxx/include/__algorithm/clamp.h +++ b/libcxx/include/__algorithm/clamp.h @@ -26,7 +26,7 @@ clamp(_LIBCPP_LIFETIMEBOUND const _Tp& __v, _LIBCPP_LIFETIMEBOUND const _Tp& __lo, _LIBCPP_LIFETIMEBOUND const _Tp& __hi, _Compare __comp) { - _LIBCPP_ASSERT_UNCATEGORIZED(!__comp(__hi, __lo), "Bad bounds passed to std::clamp"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__comp(__hi, __lo), "Bad bounds passed to std::clamp"); return __comp(__v, __lo) ? __lo : __comp(__hi, __v) ? __hi : __v; } diff --git a/libcxx/include/__algorithm/ranges_clamp.h b/libcxx/include/__algorithm/ranges_clamp.h index e6c86207254a19..a1185e7278f0ed 100644 --- a/libcxx/include/__algorithm/ranges_clamp.h +++ b/libcxx/include/__algorithm/ranges_clamp.h @@ -34,8 +34,9 @@ struct __fn { indirect_strict_weak_order> _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr const _Type& operator()( const _Type& __value, const _Type& __low, const _Type& __high, _Comp __comp = {}, _Proj __proj = {}) const { -_LIBCPP_ASSERT_UNCATEGORIZED(!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))), - "Bad bounds passed to std::ranges::clamp"); +_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( +!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))), +"Bad bounds passed to std::ranges::clamp"); auto&& __projected = std::invoke(__proj, __value); if (std::invoke(__comp, std::forward(__projected), std::invoke(__proj, __low))) diff --git a/libcxx/include/__bit/bit_ceil.h b/libcxx/include/__bit/bit_ceil.h index 17fe06aa41ccd8..77fa739503bc58 100644 --- a/libcxx/include/__bit/bit_ceil.h +++ b/libcxx/include/__bit/bit_ceil.h @@ -28,7 +28,7 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Tp __bit_ceil(_Tp __t) no if (__t < 2) return 1; const unsigned __n = numeric_limits<_Tp>::digits - std::__countl_zero((_Tp)(__t - 1u)); - _LIBCPP_ASSERT_UNCATEGORIZED(__n != numeric_limits<_Tp>::digits, "Bad input to bit_ceil"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__n != numeric_limits<_Tp>::digits, "Bad input to bit_ceil"); if constexpr (sizeof(_Tp) >= sizeof(unsigned)) return _Tp{1} << __n; diff --git a/libcxx/include/__config b/libcxx/include/__config index 082c73e672c749..9ba4fce834132f 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -283,6 +283,14 @@ // - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure // the containers have compatible allocators. // +// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments +// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the +// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g. +// a string view where only a subset of elements is possible to access). This doesn't cause an immediate issue within +// the library but is always a logic bug and is likely to cause problems within user code. +// This is somewhat of a catch-all (or fallback) category -- it
[libcxx] [clang-tools-extra] [clang] [llvm] [libc++][hardening] Categorize assertions that produce incorrect results (PR #77183)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77183 >From 2d62194c2c30b5072c8d42bf30d3b5163b1eb844 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 5 Jan 2024 23:34:42 -0800 Subject: [PATCH 1/2] [libc++][hardening] Categorize assertions that produce incorrect results Introduce a new `argument-within-domain` category that covers cases where the given arguments make it impossible to produce a correct result (or create a valid object in case of constructors). While the incorrect result doesn't create an immediate problem within the library (like e.g. a null pointer dereference would), it always indicates a logic error in user code and is highly likely to lead to a bug in the program once the value is used. --- libcxx/include/__algorithm/clamp.h | 2 +- libcxx/include/__algorithm/ranges_clamp.h| 5 +++-- libcxx/include/__bit/bit_ceil.h | 2 +- libcxx/include/__config | 14 +- libcxx/include/__hash_table | 2 +- libcxx/include/__memory/assume_aligned.h | 3 ++- libcxx/include/__numeric/gcd_lcm.h | 2 +- libcxx/include/barrier | 12 ++-- libcxx/include/latch | 10 +- libcxx/include/semaphore | 8 libcxx/include/string_view | 7 +-- libcxx/src/filesystem/operations.cpp | 5 ++--- libcxx/src/include/to_chars_floating_point.h | 2 +- 13 files changed, 45 insertions(+), 29 deletions(-) diff --git a/libcxx/include/__algorithm/clamp.h b/libcxx/include/__algorithm/clamp.h index 1631b2673c3faf4..003bf70dd4f01db 100644 --- a/libcxx/include/__algorithm/clamp.h +++ b/libcxx/include/__algorithm/clamp.h @@ -26,7 +26,7 @@ clamp(_LIBCPP_LIFETIMEBOUND const _Tp& __v, _LIBCPP_LIFETIMEBOUND const _Tp& __lo, _LIBCPP_LIFETIMEBOUND const _Tp& __hi, _Compare __comp) { - _LIBCPP_ASSERT_UNCATEGORIZED(!__comp(__hi, __lo), "Bad bounds passed to std::clamp"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__comp(__hi, __lo), "Bad bounds passed to std::clamp"); return __comp(__v, __lo) ? __lo : __comp(__hi, __v) ? __hi : __v; } diff --git a/libcxx/include/__algorithm/ranges_clamp.h b/libcxx/include/__algorithm/ranges_clamp.h index e6c86207254a19f..a1185e7278f0ed4 100644 --- a/libcxx/include/__algorithm/ranges_clamp.h +++ b/libcxx/include/__algorithm/ranges_clamp.h @@ -34,8 +34,9 @@ struct __fn { indirect_strict_weak_order> _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr const _Type& operator()( const _Type& __value, const _Type& __low, const _Type& __high, _Comp __comp = {}, _Proj __proj = {}) const { -_LIBCPP_ASSERT_UNCATEGORIZED(!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))), - "Bad bounds passed to std::ranges::clamp"); +_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( +!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))), +"Bad bounds passed to std::ranges::clamp"); auto&& __projected = std::invoke(__proj, __value); if (std::invoke(__comp, std::forward(__projected), std::invoke(__proj, __low))) diff --git a/libcxx/include/__bit/bit_ceil.h b/libcxx/include/__bit/bit_ceil.h index 17fe06aa41ccd87..77fa739503bc58c 100644 --- a/libcxx/include/__bit/bit_ceil.h +++ b/libcxx/include/__bit/bit_ceil.h @@ -28,7 +28,7 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Tp __bit_ceil(_Tp __t) no if (__t < 2) return 1; const unsigned __n = numeric_limits<_Tp>::digits - std::__countl_zero((_Tp)(__t - 1u)); - _LIBCPP_ASSERT_UNCATEGORIZED(__n != numeric_limits<_Tp>::digits, "Bad input to bit_ceil"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__n != numeric_limits<_Tp>::digits, "Bad input to bit_ceil"); if constexpr (sizeof(_Tp) >= sizeof(unsigned)) return _Tp{1} << __n; diff --git a/libcxx/include/__config b/libcxx/include/__config index 082c73e672c7492..9ba4fce834132f1 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -283,6 +283,14 @@ // - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure // the containers have compatible allocators. // +// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments +// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the +// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g. +// a string view where only a subset of elements is possible to access). This doesn't cause an immediate issue within +// the library but is always a logic bug and is likely to cause problems within user code. +// This is somewhat of a catch-all (or fallback)
[clang-tools-extra] [clang] [llvm] [libcxx] [libc++][hardening] Classify assertions related to leaks and syscalls. (PR #77164)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77164 >From e28e7b3e1337cb960cdc8028a70a43740fa7d636 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 21 Dec 2023 14:36:47 -0800 Subject: [PATCH 1/4] [libc++][hardening] Classify assertions related to leaks and syscalls. Introduce two new categories: - `_LIBCPP_ASSERT_VALID_DEALLOCATION`; - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL`. --- libcxx/include/__config | 16 libcxx/include/__coroutine/coroutine_handle.h| 16 .../__memory_resource/polymorphic_allocator.h| 3 ++- libcxx/src/filesystem/operations.cpp | 8 +--- libcxx/src/memory_resource.cpp | 3 ++- libcxx/src/mutex.cpp | 8 +--- 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 082c73e672c749..4d74b564864272 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -280,6 +280,14 @@ // - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the // given ranges do not overlap. // +// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object +// was allocated by the given allocator). Violating this category typically results in a memory leak. +// +// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API (e.g. a syscall) doesn't fail in +// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like +// attempting to unlock an unlocked mutex in pthreads). We generally don't expect these failures to compromize memory +// safety or otherwise create an immediate security issue. +// // - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure // the containers have compatible allocators. // @@ -327,6 +335,8 @@ _LIBCPP_HARDENING_MODE_DEBUG // Overlapping ranges will make algorithms produce incorrect results but don't directly lead to a security // vulnerability. #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) @@ -341,6 +351,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) @@ -356,6 +368,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message) @@ -370,6 +384,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression) #
[libcxx] [llvm] [clang] [clang-tools-extra] [libc++][hardening] Classify assertions related to leaks and syscalls. (PR #77164)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77164 >From e28e7b3e1337cb960cdc8028a70a43740fa7d636 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 21 Dec 2023 14:36:47 -0800 Subject: [PATCH 1/3] [libc++][hardening] Classify assertions related to leaks and syscalls. Introduce two new categories: - `_LIBCPP_ASSERT_VALID_DEALLOCATION`; - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL`. --- libcxx/include/__config | 16 libcxx/include/__coroutine/coroutine_handle.h| 16 .../__memory_resource/polymorphic_allocator.h| 3 ++- libcxx/src/filesystem/operations.cpp | 8 +--- libcxx/src/memory_resource.cpp | 3 ++- libcxx/src/mutex.cpp | 8 +--- 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 082c73e672c749..4d74b564864272 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -280,6 +280,14 @@ // - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the // given ranges do not overlap. // +// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object +// was allocated by the given allocator). Violating this category typically results in a memory leak. +// +// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API (e.g. a syscall) doesn't fail in +// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like +// attempting to unlock an unlocked mutex in pthreads). We generally don't expect these failures to compromize memory +// safety or otherwise create an immediate security issue. +// // - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure // the containers have compatible allocators. // @@ -327,6 +335,8 @@ _LIBCPP_HARDENING_MODE_DEBUG // Overlapping ranges will make algorithms produce incorrect results but don't directly lead to a security // vulnerability. #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) @@ -341,6 +351,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) @@ -356,6 +368,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message) @@ -370,6 +384,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression) #
[libcxx] [llvm] [clang] [clang-tools-extra] [libc++][hardening] Don't trigger redundant checks in the fast mode. (PR #77176)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77176 >From f86839d0bfc8b2070127dc3b2c609c2b3f7239ad Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 5 Jan 2024 20:08:27 -0800 Subject: [PATCH 1/2] [libc++][hardening] Don't trigger redundant checks in the fast mode. Sometimes we essentially check the same condition twice -- for example, a class might check that an index into its vector member variable is valid before accessing it, but `vector::operator[]` contains the same check. These "redundant" checks allow catching errors closer to the source and providing a better error message, but they also impose additional overhead. Marking the "early" checks as redundant allows ignoring them in the fast mode (while still getting a guaranteed trap) while still getting better error messages in the extensive mode and above. Introducing a separate wrapper macro allows making the concept of redundant assertions orthogonal to assertion categories and retaining the actual category of a check. This is a follow-up to https://github.com/llvm/llvm-project/pull/75918, specifically to [this discussion](https://github.com/llvm/llvm-project/pull/75918#discussion_r1434493455). --- libcxx/include/__config | 16 .../include/__filesystem/directory_iterator.h | 3 ++- libcxx/include/__iterator/next.h| 5 +++-- libcxx/include/__iterator/prev.h| 5 +++-- libcxx/include/__mdspan/layout_left.h | 5 +++-- libcxx/include/__mdspan/layout_right.h | 5 +++-- libcxx/include/__mdspan/layout_stride.h | 5 +++-- libcxx/include/__ranges/chunk_by_view.h | 17 +++-- libcxx/include/__ranges/drop_while_view.h | 9 + libcxx/include/__ranges/filter_view.h | 5 +++-- libcxx/include/regex| 3 ++- 11 files changed, 54 insertions(+), 24 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 082c73e672c749..b20e8abed0939c 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -290,6 +290,18 @@ // user input. // // - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet. +// +// In addition to these categories, `_LIBCPP_REDUNDANT_ASSERTION` should be used to wrap assertions that duplicate other +// assertions (for example, a range view might check that its `optional` data member holds a value before dereferencing +// it, but this is already checked by `optional` itself). Redundant assertions incur an additional performance overhead +// and don't provide any extra security benefit, but catching an error earlier allows halting the program closer to the +// root cause and giving the user an error message that contains more context. Due to these tradeoffs, redundant +// assertions are disabled in the fast mode but are enabled in the extensive mode and above. Thus, going back to the +// example above, if a view attempts to dereference an empty optional member variable: +// - in the fast mode, the program will only perform one check and will trap inside the optional (with an error +// amounting to "Attempting to dereference an empty optional"); +// - in the extensive mode, the program will normally perform two checks (in the non-error case), and if the optional is +// empty, it will trap inside the view (with an error like "`foo_view` doesn't have a valid predicate"). // clang-format off # define _LIBCPP_HARDENING_MODE_NONE (1 << 1) @@ -331,6 +343,7 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_REDUNDANT_ASSERTION(expression) _LIBCPP_ASSUME(expression) // Extensive hardening mode checks. @@ -344,6 +357,7 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_REDUNDANT_ASSERTION(expression) expression // Disabled checks. #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) @@ -360,6 +374,7 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression,
[clang-tools-extra] [libcxx] [llvm] [clang] [libc++][hardening] Classify assertions related to leaks and syscalls. (PR #77164)
https://github.com/var-const updated https://github.com/llvm/llvm-project/pull/77164 >From e28e7b3e1337cb960cdc8028a70a43740fa7d636 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 21 Dec 2023 14:36:47 -0800 Subject: [PATCH 1/2] [libc++][hardening] Classify assertions related to leaks and syscalls. Introduce two new categories: - `_LIBCPP_ASSERT_VALID_DEALLOCATION`; - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL`. --- libcxx/include/__config | 16 libcxx/include/__coroutine/coroutine_handle.h| 16 .../__memory_resource/polymorphic_allocator.h| 3 ++- libcxx/src/filesystem/operations.cpp | 8 +--- libcxx/src/memory_resource.cpp | 3 ++- libcxx/src/mutex.cpp | 8 +--- 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 082c73e672c749..4d74b564864272 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -280,6 +280,14 @@ // - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the // given ranges do not overlap. // +// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object +// was allocated by the given allocator). Violating this category typically results in a memory leak. +// +// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API (e.g. a syscall) doesn't fail in +// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like +// attempting to unlock an unlocked mutex in pthreads). We generally don't expect these failures to compromize memory +// safety or otherwise create an immediate security issue. +// // - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure // the containers have compatible allocators. // @@ -327,6 +335,8 @@ _LIBCPP_HARDENING_MODE_DEBUG // Overlapping ranges will make algorithms produce incorrect results but don't directly lead to a security // vulnerability. #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) @@ -341,6 +351,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) @@ -356,6 +368,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +#define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) #define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message) @@ -370,6 +384,8 @@ _LIBCPP_HARDENING_MODE_DEBUG #define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression) #define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression) #
[llvm] [clang-tools-extra] [clang] [libcxx] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -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, c++20 + +// template +// struct in_value_result; + +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct A { + explicit A(int); +}; +// no implicit conversion +static_assert(!std::is_constructible_v, std::ranges::in_value_result>); + +struct B { + B(int); +}; +// implicit conversion +static_assert(std::is_constructible_v, std::ranges::in_value_result>); +static_assert(std::is_constructible_v, std::ranges::in_value_result&>); +static_assert( +std::is_constructible_v, const std::ranges::in_value_result>); +static_assert( +std::is_constructible_v, const std::ranges::in_value_result&>); + +struct C { + C(int&); +}; +static_assert(!std::is_constructible_v, std::ranges::in_value_result&>); + +// has to be convertible via const& +static_assert(std::is_convertible_v&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&&, std::ranges::in_value_result>); + +// should be move constructible +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); + +// should not copy constructible with move-only type var-const wrote: I fully agree that adding this to a project-wide style guide would be very useful (to be clear, I don't mean to imply it has to be a comprehensive huge guide, even if it documents just a few randomly chosen aspects, it's already helpful and we can always expand later). We do have a ["Coding standards"](https://libcxx.llvm.org/Contributing.html#coding-standards) section in the `Contributing` document -- we might want to add a new page and link it from that section. Thanks for taking this on! https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libcxx] [clang-tools-extra] [llvm] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
var-const wrote: > I see @var-const has "requested changes" set, but I feel we've addressed the > one unresolved comment of his. @EricWF In fact, this patch changed quite significantly since I last looked at it (based on your feedback, I believe), so I would have appreciated being able to do another round of review before this was merged. https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [clang-tools-extra] [libcxx] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -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, c++20 + +// template +// struct in_value_result; + +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct A { + explicit A(int); +}; +// no implicit conversion +static_assert(!std::is_constructible_v, std::ranges::in_value_result>); + +struct B { + B(int); +}; +// implicit conversion +static_assert(std::is_constructible_v, std::ranges::in_value_result>); +static_assert(std::is_constructible_v, std::ranges::in_value_result&>); +static_assert( +std::is_constructible_v, const std::ranges::in_value_result>); +static_assert( +std::is_constructible_v, const std::ranges::in_value_result&>); + +struct C { + C(int&); +}; +static_assert(!std::is_constructible_v, std::ranges::in_value_result&>); + +// has to be convertible via const& +static_assert(std::is_convertible_v&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&&, std::ranges::in_value_result>); + +// should be move constructible +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); + +// should not copy constructible with move-only type +static_assert(!std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); + +struct NotConvertible {}; +// conversions should not work if there is no conversion +static_assert( +!std::is_convertible_v, std::ranges::in_value_result>); +static_assert( +!std::is_convertible_v, std::ranges::in_value_result>); + +template +struct ConvertibleFrom { + constexpr ConvertibleFrom(T c) : content{c} {} + T content; +}; + +constexpr bool test() { + { var-const wrote: Can you add a brief comment to explain what each of these cases is intended to test? https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libcxx] [llvm] [clang-tools-extra] [clang] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -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, c++20 + +// template +// struct in_value_result; + +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct A { + explicit A(int); +}; +// no implicit conversion +static_assert(!std::is_constructible_v, std::ranges::in_value_result>); + +struct B { + B(int); +}; +// implicit conversion +static_assert(std::is_constructible_v, std::ranges::in_value_result>); +static_assert(std::is_constructible_v, std::ranges::in_value_result&>); +static_assert( +std::is_constructible_v, const std::ranges::in_value_result>); +static_assert( +std::is_constructible_v, const std::ranges::in_value_result&>); + +struct C { + C(int&); +}; +static_assert(!std::is_constructible_v, std::ranges::in_value_result&>); + +// has to be convertible via const& +static_assert(std::is_convertible_v&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&&, std::ranges::in_value_result>); + +// should be move constructible +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); + +// should not copy constructible with move-only type var-const wrote: Ultranit: `s/should not copy constructible/should not be copy constructible/`. https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libcxx] [clang] [clang-tools-extra] [llvm] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -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, c++20 + +// template +// struct in_value_result; + +#include +#include +#include +#include + +#include "MoveOnly.h" + +struct A { + explicit A(int); +}; +// no implicit conversion +static_assert(!std::is_constructible_v, std::ranges::in_value_result>); + +struct B { + B(int); +}; +// implicit conversion +static_assert(std::is_constructible_v, std::ranges::in_value_result>); +static_assert(std::is_constructible_v, std::ranges::in_value_result&>); +static_assert( +std::is_constructible_v, const std::ranges::in_value_result>); +static_assert( +std::is_constructible_v, const std::ranges::in_value_result&>); + +struct C { + C(int&); +}; +static_assert(!std::is_constructible_v, std::ranges::in_value_result&>); + +// has to be convertible via const& +static_assert(std::is_convertible_v&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&&, std::ranges::in_value_result>); +static_assert( +std::is_convertible_v&&, std::ranges::in_value_result>); + +// should be move constructible +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); + +// should not copy constructible with move-only type +static_assert(!std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); + +struct NotConvertible {}; +// conversions should not work if there is no conversion +static_assert( +!std::is_convertible_v, std::ranges::in_value_result>); +static_assert( +!std::is_convertible_v, std::ranges::in_value_result>); + +template +struct ConvertibleFrom { + constexpr ConvertibleFrom(T c) : content{c} {} + T content; +}; + +constexpr bool test() { + { +std::ranges::in_value_result res{10, 0.}; +assert(res.in == 10); +assert(res.value == 0.); +std::ranges::in_value_result, ConvertibleFrom> res2 = res; +assert(res2.in.content == 10); +assert(res2.value.content == 0.); + } var-const wrote: Optional nit: can you separate different test cases with blank lines? https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [llvm] [libcxx] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
https://github.com/var-const commented: This patch has changed substantially since I last reviewed it. I'll send more feedback in a follow-up review. https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [llvm] [libcxx] [clang] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -0,0 +1,315 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, +// indirectly-binary-left-foldable F> +// constexpr see below ranges::fold_left_with_iter(I first, S last, T init, F f); +// +// template> F> +// constexpr see below ranges::fold_left_with_iter(R&& r, T init, F f); + +// template S, class T, +// indirectly-binary-left-foldable F> +// constexpr see below ranges::fold_left(I first, S last, T init, F f); +// +// template> F> +// constexpr see below ranges::fold_left(R&& r, T init, F f); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_range.h" +#include "invocable_with_telemetry.h" +#include "maths.h" + +using std::ranges::fold_left; +using std::ranges::fold_left_with_iter; + +template +concept is_in_value_result = +std::same_as, T>>; + +template +concept is_dangling_with = std::same_as>; + +struct Long { var-const wrote: Nit: the name `Long` seems counterintuitive. https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [libcxx] [clang-tools-extra] [clang] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -0,0 +1,89 @@ +//===--===// +// +// 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 TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H var-const wrote: No action required: we already have at least `TracedCopyMove` and `TracedAssignment` in `support/copy_move_types.h`, and I'm almost confident there are a few other similar types defined more locally in various tests. Is this class intended to supersede those? Or to provide C++20-only benefits? https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [llvm] [libcxx] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -0,0 +1,118 @@ +// -*- C++ -*- +//===--===// +// +// 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 _LIBCPP___ALGORITHM_FOLD_H +#define _LIBCPP___ALGORITHM_FOLD_H + +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/invocable.h> +#include <__concepts/movable.h> +#include <__config> +#include <__functional/invoke.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__type_traits/decay.h> +#include <__type_traits/invoke.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { +template +struct in_value_result { + _Ip in; + _Tp result; +}; + +template +using fold_left_with_iter_result = in_value_result<_Ip, _Tp>; + +template > +concept __indirectly_binary_left_foldable_impl = +convertible_to<_Rp, _Up> &&// +movable<_Tp> &&// +movable<_Up> &&// +convertible_to<_Tp, _Up> &&// +invocable<_Fp&, _Up, iter_reference_t<_Ip>> && // +assignable_from<_Up&, invoke_result_t<_Fp&, _Up, iter_reference_t<_Ip>>>; + +template +concept __indirectly_binary_left_foldable = +copy_constructible<_Fp> && // +invocable<_Fp&, _Tp, iter_reference_t<_Ip>> && // +__indirectly_binary_left_foldable_impl<_Fp, _Tp, _Ip, invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>; + +struct __fold_left_with_iter { + template _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto + operator()(_Ip __first, _Sp __last, _Tp __init, _Fp __f) { +using _Up = decay_t>>; + +if (__first == __last) { + return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), _Up(std::move(__init))}; +} + +_Up __result = std::invoke(__f, std::move(__init), *__first); +for (++__first; __first != __last; ++__first) { + __result = std::invoke(__f, std::move(__result), *__first); +} + +return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), std::move(__result)}; + } + + template > _Fp> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Fp __f) { +auto __result = operator()(ranges::begin(__r), ranges::end(__r), std::move(__init), std::ref(__f)); + +using _Up = decay_t>>; +return fold_left_with_iter_result, _Up>{ +std::move(__result.in), std::move(__result.result)}; + } +}; + +inline namespace __cpo { +inline constexpr auto fold_left_with_iter = __fold_left_with_iter(); +} // namespace __cpo + +struct __fold_left { + template _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp> var-const wrote: @EricWF This discussion has [already happened](https://discord.com/channels/636084430946959380/956590603808931870), and I can confirm that the outcome of it was to use `_Iter` and `_Sent`. Maintaining consistency is one of the purposes of doing a code review, and I don't think the fact that our code base is not perfect in this regard allows dismissing that. If you would like to reopen that discussion, you are also quite welcome to come up with a new proposal. https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libcxx] [llvm] [clang-tools-extra] [clang] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -0,0 +1,118 @@ +// -*- C++ -*- +//===--===// +// +// 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 _LIBCPP___ALGORITHM_FOLD_H +#define _LIBCPP___ALGORITHM_FOLD_H + +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/invocable.h> +#include <__concepts/movable.h> +#include <__config> +#include <__functional/invoke.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__type_traits/decay.h> +#include <__type_traits/invoke.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { +template +struct in_value_result { + _Ip in; + _Tp result; +}; + +template +using fold_left_with_iter_result = in_value_result<_Ip, _Tp>; + +template > +concept __indirectly_binary_left_foldable_impl = +convertible_to<_Rp, _Up> &&// +movable<_Tp> &&// +movable<_Up> &&// +convertible_to<_Tp, _Up> &&// +invocable<_Fp&, _Up, iter_reference_t<_Ip>> && // +assignable_from<_Up&, invoke_result_t<_Fp&, _Up, iter_reference_t<_Ip>>>; + +template +concept __indirectly_binary_left_foldable = +copy_constructible<_Fp> && // +invocable<_Fp&, _Tp, iter_reference_t<_Ip>> && // +__indirectly_binary_left_foldable_impl<_Fp, _Tp, _Ip, invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>; + +struct __fold_left_with_iter { + template _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto + operator()(_Ip __first, _Sp __last, _Tp __init, _Fp __f) { +using _Up = decay_t>>; + +if (__first == __last) { + return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), _Up(std::move(__init))}; +} + +_Up __result = std::invoke(__f, std::move(__init), *__first); +for (++__first; __first != __last; ++__first) { + __result = std::invoke(__f, std::move(__result), *__first); +} + +return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), std::move(__result)}; + } + + template > _Fp> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Fp __f) { +auto __result = operator()(ranges::begin(__r), ranges::end(__r), std::move(__init), std::ref(__f)); + +using _Up = decay_t>>; +return fold_left_with_iter_result, _Up>{ +std::move(__result.in), std::move(__result.result)}; + } +}; + +inline namespace __cpo { +inline constexpr auto fold_left_with_iter = __fold_left_with_iter(); +} // namespace __cpo + +struct __fold_left { + template _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp> var-const wrote: IIUC, we did have that discussion at the time, and I think `_Iter` and `_Sent` were the resolution. https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [libcxx] [clang-tools-extra] [clang] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -0,0 +1,259 @@ +//===--===// +// +// 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, c++20 + +// Checks that `std::ranges::fold_left_with_iter`'s requirements reject parameters that don't meet var-const wrote: Nit: this comment should also mention `fold_left`. Consider also copying the declaration of the algorithms into the comment, so that the exact requirements are easy to see. https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [libcxx] [clang-tools-extra] [clang] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
https://github.com/var-const edited https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libcxx] [clang-tools-extra] [llvm] [libcxx] adds ranges::fold_left_with_iter and ranges::fold_left (PR #75259)
@@ -0,0 +1,89 @@ +//===--===// +// +// 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 TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H +#define TEST_SUPPORT_INVOCABLE_WITH_TELEMETRY_H + +#include +#include +#include +#include + +#if TEST_STD_VER < 20 +# error invocable_with_telemetry requires C++20 +#else +struct invocable_telemetry { var-const wrote: Is there precedent for calling this kind of measurements "telemetry"? I've only ever seen "telemetry" to describe a somewhat higher-level and heavier-weight kind of measurements about the behavior of the application in general, usually involving transmitting data over a network (which seems to be implied by the `tele` part). https://github.com/llvm/llvm-project/pull/75259 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [lldb] [mlir] [clang-tools-extra] [libcxx] [compiler-rt] [lld] [clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,303 @@ +//===--===// +// +// 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, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsSubrangeIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { + std::ranges::contains_subrange(first1, last1, first2, last2); +}; + +static_assert(HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); // not indirectly comparable +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); + +template > +concept HasContainsSubrangeR = requires(Range1&& range1, Range2&& range2) { + std::ranges::contains_subrange(std::forward(range1), std::forward(range2)); }; + +static_assert(HasContainsSubrangeR>); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR, UncheckedRange>); // not indirectly comparable +static_assert(!HasContainsSubrangeR, ForwardRangeNotDerivedFrom>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotIncrementable>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelSemiregular>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelEqualityComparableWith>); + +template +constexpr void test_iterators() { + { // simple tests +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 5}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = + std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = std::ranges::contains_subrange(whole, subrange); + assert(ret); +} + } + + { // no match +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(!ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(!ret); +} + } + + { // range consists of just one element +int a[] = {3}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(!ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(!ret); +} + } + + { // subrange consists of just one element +int a[] = {23, 1, 20, 3, 54, 2}; +int p[] = {3}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(ret); +} + } + + { // range has zero length +int a[] = {}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(),
[flang] [mlir] [compiler-rt] [lldb] [clang] [llvm] [lld] [clang-tools-extra] [libunwind] [libc] [openmp] [libcxxabi] [libcxx] [libc++] Implement ranges::contains (PR #65148)
@@ -34,6 +35,10 @@ struct __identity { template <> struct __is_identity<__identity> : true_type {}; +template <> var-const wrote: Can you elaborate on your concerns here? https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[openmp] [clang-tools-extra] [clang] [libunwind] [libc] [mlir] [llvm] [lld] [libcxx] [lldb] [compiler-rt] [libcxxabi] [flang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,195 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); +static_assert(!HasContainsIt, sentinel_wrapper>>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range&& range) { std::ranges::contains(std::forward(range), ValT{}); }; + +static_assert(!HasContainsR); +static_assert(HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +ValueT a[] = {1, 2, 3, 4, 5, 6}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); +{ + std::same_as decltype(auto) ret = std::ranges::contains(whole.begin(), whole.end(), 3); + assert(ret); +} +{ + std::same_as decltype(auto) ret = std::ranges::contains(whole, 3); + assert(ret); +} + } + + { // check that a range with a single element works +ValueT a[] = {32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that an empty range works +ValueT a[] = {}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 1); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 1); + assert(!ret); +} + } + + { // check that the first element matches +ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that the last element matches +ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // no match +ValueT a[] = {13, 1, 21, 4, 5}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 10); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 10); + assert(!ret); +} + } + + { // check that the projections are used +int a[] = {1, 9, 0, 13, 25}; +{ + bool ret = std::ranges::contains(a, a + 5, -13, [&](int i) { return i * -1; }); + assert(ret); +} +{ + auto range = std::ranges::subrange(a, a + 5); + bool ret = std::ranges::contains(range, -13, [&](int i) { return i * -1; }); + assert(ret); +} + } +} + +constexpr bool test() { + types::for_each(types::type_list{}, [] { +types::for_each(types::cpp20_input_iterator_list{}, [] { + if constexpr (std::forward_iterator) +test_iterators(); + test_iterators>(); + test_iterators>(); +}); + }); + + { // count invocations of the projection var-const wrote: Can you provide some examples?
[flang] [mlir] [compiler-rt] [lldb] [clang] [llvm] [lld] [clang-tools-extra] [libunwind] [libc] [openmp] [libcxxabi] [libcxx] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,61 @@ +//===--===// +// +// 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 _LIBCPP___ALGORITHM_RANGES_CONTAINS_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_H + +#include <__algorithm/ranges_find.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __contains { +struct __fn { + template _Sent, class _Type, class _Proj = identity> +requires indirect_binary_predicate, const _Type*> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) const { +return ranges::find(std::move(__first), std::move(__last), __value, std::ref(__proj)) != __last; var-const wrote: Thanks for catching this! https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[lld] [llvm] [mlir] [compiler-rt] [clang] [libcxx] [clang-tools-extra] [lldb] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
https://github.com/var-const unassigned https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [compiler-rt] [lldb] [clang] [clang-tools-extra] [lld] [mlir] [libcxx] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
https://github.com/var-const unassigned https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libcxxabi] [libc] [mlir] [clang-tools-extra] [lld] [llvm] [libcxx] [libunwind] [flang] [clang] [compiler-rt] [lldb] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,49 @@ +//===--===// var-const wrote: Thanks a lot for adding the benchmark! Can you please post the results you're getting in the patch/commit description for potential future reference? https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libunwind] [llvm] [libcxxabi] [compiler-rt] [clang-tools-extra] [lld] [libcxx] [flang] [lldb] [clang] [libc] [mlir] [libc++] Implement ranges::contains (PR #65148)
https://github.com/var-const edited https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[mlir] [flang] [llvm] [libc] [libunwind] [lldb] [libcxxabi] [clang] [libcxx] [lld] [clang-tools-extra] [compiler-rt] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,49 @@ +//===--===// +// +// 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 +// +//===--===// + +#include +#include +#include + +#include "test_iterators.h" var-const wrote: Nit: please move the `` include above so that it goes right after ``. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libunwind] [llvm] [clang-tools-extra] [clang] [mlir] [libc] [lldb] [libcxx] [lld] [compiler-rt] [libcxxabi] [flang] [libc++] Implement ranges::contains (PR #65148)
https://github.com/var-const approved this pull request. Thanks a lot for working on this! LGTM with a couple simple comments. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [libc++][hardening] Fix references to old names for hardening modes (PR #71743)
https://github.com/var-const closed https://github.com/llvm/llvm-project/pull/71743 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [libc++][hardening] Fix references to old names for hardening modes (PR #71743)
https://github.com/var-const created https://github.com/llvm/llvm-project/pull/71743 This should fix some builds broken by https://github.com/llvm/llvm-project/pull/70575 >From 11dad502fa66c6f7d0377a554c7f22ef21a9faee Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 8 Nov 2023 13:12:38 -1000 Subject: [PATCH] [libc++][hardening] Fix references to old names for hardening modes This should fix some builds broken by https://github.com/llvm/llvm-project/pull/70575 --- clang/cmake/caches/Fuchsia-stage2.cmake| 2 +- clang/cmake/caches/Fuchsia.cmake | 2 +- llvm/cmake/modules/HandleLLVMOptions.cmake | 8 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index a4d2926559eee7f..4b9085d99378c6f 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -81,7 +81,7 @@ if(APPLE) set(LIBCXX_ABI_VERSION 2 CACHE STRING "") set(LIBCXX_ENABLE_SHARED OFF CACHE BOOL "") set(LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "") - set(LIBCXX_HARDENING_MODE "unchecked" CACHE STRING "") + set(LIBCXX_HARDENING_MODE "none" CACHE STRING "") set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "") set(RUNTIMES_CMAKE_ARGS "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13;-DCMAKE_OSX_ARCHITECTURES=arm64|x86_64" CACHE STRING "") endif() diff --git a/clang/cmake/caches/Fuchsia.cmake b/clang/cmake/caches/Fuchsia.cmake index 4c9cd12101d478a..dad434be720da11 100644 --- a/clang/cmake/caches/Fuchsia.cmake +++ b/clang/cmake/caches/Fuchsia.cmake @@ -116,7 +116,7 @@ else() set(LIBCXX_ABI_VERSION 2 CACHE STRING "") set(LIBCXX_ENABLE_SHARED OFF CACHE BOOL "") set(LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "") - set(LIBCXX_HARDENING_MODE "unchecked" CACHE STRING "") + set(LIBCXX_HARDENING_MODE "none" CACHE STRING "") set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "") set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "") set(RUNTIMES_CMAKE_ARGS "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13;-DCMAKE_OSX_ARCHITECTURES=arm64|x86_64" CACHE STRING "") diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake index ca7cedd6e4afff4..6a3c49edc912ded 100644 --- a/llvm/cmake/modules/HandleLLVMOptions.cmake +++ b/llvm/cmake/modules/HandleLLVMOptions.cmake @@ -111,12 +111,12 @@ if( LLVM_ENABLE_ASSERTIONS ) endif() # Enable assertions in libstdc++. add_compile_definitions(_GLIBCXX_ASSERTIONS) - # Cautiously enable the safe hardened mode in libc++. + # Cautiously enable the extensive hardening mode in libc++. if((DEFINED LIBCXX_HARDENING_MODE) AND - (NOT LIBCXX_HARDENING_MODE STREQUAL "safe")) -message(WARNING "LLVM_ENABLE_ASSERTIONS implies LIBCXX_HARDENING_MODE \"safe\" but is overriden from command line with value \"${LIBCXX_HARDENING_MODE}\".") + (NOT LIBCXX_HARDENING_MODE STREQUAL "extensive")) +message(WARNING "LLVM_ENABLE_ASSERTIONS implies LIBCXX_HARDENING_MODE \"extensive\" but is overriden from command line with value \"${LIBCXX_HARDENING_MODE}\".") else() -set(LIBCXX_HARDENING_MODE "safe") +set(LIBCXX_HARDENING_MODE "extensive") endif() endif() ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,303 @@ +//===--===// +// +// 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, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsSubrangeIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { + std::ranges::contains_subrange(first1, last1, first2, last2); +}; + +static_assert(HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); // not indirectly comparable +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); + +template > +concept HasContainsSubrangeR = requires(Range1&& range1, Range2&& range2) { + std::ranges::contains_subrange(std::forward(range1), std::forward(range2)); }; + +static_assert(HasContainsSubrangeR>); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR, UncheckedRange>); // not indirectly comparable +static_assert(!HasContainsSubrangeR, ForwardRangeNotDerivedFrom>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotIncrementable>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelSemiregular>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelEqualityComparableWith>); + +template +constexpr void test_iterators() { + { // simple tests +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 5}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = + std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = std::ranges::contains_subrange(whole, subrange); + assert(ret); +} + } + + { // no match +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(!ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(!ret); +} + } + + { // range consists of just one element +int a[] = {3}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(!ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(!ret); +} + } + + { // subrange consists of just one element +int a[] = {23, 1, 20, 3, 54, 2}; +int p[] = {3}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(ret); +} + } + + { // range has zero length +int a[] = {}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(),
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,303 @@ +//===--===// +// +// 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, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" var-const wrote: Is this header used? https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
https://github.com/var-const requested changes to this pull request. Thank you for the patch! https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
https://github.com/var-const edited https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,303 @@ +//===--===// +// +// 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, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include var-const wrote: Nit: `` seems unused. https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,303 @@ +//===--===// +// +// 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, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsSubrangeIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { + std::ranges::contains_subrange(first1, last1, first2, last2); +}; + +static_assert(HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); // not indirectly comparable +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); + +template > +concept HasContainsSubrangeR = requires(Range1&& range1, Range2&& range2) { + std::ranges::contains_subrange(std::forward(range1), std::forward(range2)); }; + +static_assert(HasContainsSubrangeR>); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR, UncheckedRange>); // not indirectly comparable +static_assert(!HasContainsSubrangeR, ForwardRangeNotDerivedFrom>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotIncrementable>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelSemiregular>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelEqualityComparableWith>); + +template +constexpr void test_iterators() { + { // simple tests +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 5}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = + std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = std::ranges::contains_subrange(whole, subrange); + assert(ret); +} + } + + { // no match +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(!ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(!ret); +} + } + + { // range consists of just one element +int a[] = {3}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(!ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(!ret); +} + } + + { // subrange consists of just one element +int a[] = {23, 1, 20, 3, 54, 2}; +int p[] = {3}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(ret); +} + } + + { // range has zero length +int a[] = {}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(),
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -214,6 +214,19 @@ namespace ranges { constexpr ranges::minmax_element_result> minmax_element(R&& r, Comp comp = {}, Proj proj = {}); // since C++20 + template S1, forward_iterator I2, +sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, +class Proj2 = identity> +requires indirectly_comparable +constexpr bool ranges::contains_subrange(I1 first1, S1 last1, I2 first2, var-const wrote: Nit: please remove `ranges::` (this code block in synopsis is already within `namespace ranges`). https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,303 @@ +//===--===// +// +// 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, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsSubrangeIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { + std::ranges::contains_subrange(first1, last1, first2, last2); +}; + +static_assert(HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); // not indirectly comparable +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); + +template > +concept HasContainsSubrangeR = requires(Range1&& range1, Range2&& range2) { + std::ranges::contains_subrange(std::forward(range1), std::forward(range2)); }; + +static_assert(HasContainsSubrangeR>); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR, UncheckedRange>); // not indirectly comparable +static_assert(!HasContainsSubrangeR, ForwardRangeNotDerivedFrom>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotIncrementable>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelSemiregular>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelEqualityComparableWith>); + +template +constexpr void test_iterators() { + { // simple tests +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 5}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = var-const wrote: I think this `[[maybe_unused]]` is unnecessary because `ret` is being asserted on below. https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
https://github.com/var-const edited https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,303 @@ +//===--===// +// +// 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, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsSubrangeIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { + std::ranges::contains_subrange(first1, last1, first2, last2); +}; + +static_assert(HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); // not indirectly comparable +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); +static_assert(!HasContainsSubrangeIt); + +template > +concept HasContainsSubrangeR = requires(Range1&& range1, Range2&& range2) { + std::ranges::contains_subrange(std::forward(range1), std::forward(range2)); }; + +static_assert(HasContainsSubrangeR>); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR); +static_assert(!HasContainsSubrangeR, UncheckedRange>); // not indirectly comparable +static_assert(!HasContainsSubrangeR, ForwardRangeNotDerivedFrom>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotIncrementable>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelSemiregular>); +static_assert(!HasContainsSubrangeR, ForwardRangeNotSentinelEqualityComparableWith>); + +template +constexpr void test_iterators() { + { // simple tests +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 5}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = + std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = std::ranges::contains_subrange(whole, subrange); + assert(ret); +} + } + + { // no match +int a[] = {1, 2, 3, 4, 5, 6}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(!ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(!ret); +} + } + + { // range consists of just one element +int a[] = {3}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(!ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(!ret); +} + } + + { // subrange consists of just one element +int a[] = {23, 1, 20, 3, 54, 2}; +int p[] = {3}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end()); + assert(ret); +} +{ + bool ret = std::ranges::contains_subrange(whole, subrange); + assert(ret); +} + } + + { // range has zero length +int a[] = {}; +int p[] = {3, 4, 2}; +auto whole= std::ranges::subrange(Iter1(a), Sent1(Iter1(a))); +auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); +{ + bool ret = std::ranges::contains_subrange(whole.begin(),
[clang-tools-extra] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
https://github.com/var-const requested changes to this pull request. Thank you for the patch! https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
@@ -0,0 +1,303 @@ +//===--===// +// +// 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, c++20 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include var-const wrote: Nit: `` seems unused. https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
https://github.com/var-const edited https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++][ranges] Implement ranges::contains_subrange (PR #66963)
https://github.com/var-const edited https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains_subrange (PR #66963)
var-const wrote: > > Please make sure you add a description to your PR. This is what usually > > goes into the git log and we want those entries to be as descriptive and > > helpful for folks who read the git logs, thank you. > > Do you have any specific suggestions what should be in the message? The > libc++ "I implement something" patches are most of the time quite > straight-forward, since you can look at the standard and know what's going > on. It's also the best source, since it's the authoritative document here, > and is also what anybody who cares to actually look at the patch should check > against for correctness. +1 -- I'm in favor of descriptive commit messages in general, but in this case I'm not sure what would be useful to add beyond "Implement ranges::contains_subrange". https://github.com/llvm/llvm-project/pull/66963 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,61 @@ +//===--===// +// +// 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 _LIBCPP___ALGORITHM_RANGES_CONTAINS_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_H + +#include <__algorithm/in_in_result.h> var-const wrote: Sorry, what I mean is that a good and easy way to see if we're testing every constraint is to simply remove or comment out a constraint, run the tests and see if any tests fail. If we're testing everything properly, at least one test will fail -- conversely, if everything passes, that means a lack of test coverage. So what I'm suggesting is to temporarily remove the `projected` constraint in your local copy, run the tests and see if there are any failures. If there are no failures, please see if it's possible to add a test that checks we are using the `projected` concept there as required by the Standard. Happy to help if this explanation isn't clear! https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,61 @@ +//===--===// +// +// 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 _LIBCPP___ALGORITHM_RANGES_CONTAINS_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_H + +#include <__algorithm/in_in_result.h> var-const wrote: Sorry, what I mean is that a good and easy way to see if we're testing every constraint is to simply remove or comment out a constraint, run the tests and see if any tests fail. If we're testing everything properly, at least one test will fail -- conversely, if everything passes, that means a lack of test coverage. So what I'm suggesting is to temporarily remove the `projected` constraint in your local copy, run the tests and see if there are any failures. If there are no failures, please see if it's possible to add a test that checks we are using the `projected` concept there as required by the Standard. Happy to help if this explanation isn't clear! https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libunwind] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,61 @@ +//===--===// +// +// 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 _LIBCPP___ALGORITHM_RANGES_CONTAINS_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_H + +#include <__algorithm/in_in_result.h> var-const wrote: Sorry, what I mean is that a good and easy way to see if we're testing every constraint is to simply remove or comment out a constraint, run the tests and see if any tests fail. If we're testing everything properly, at least one test will fail -- conversely, if everything passes, that means a lack of test coverage. So what I'm suggesting is to temporarily remove the `projected` constraint in your local copy, run the tests and see if there are any failures. If there are no failures, please see if it's possible to add a test that checks we are using the `projected` concept there as required by the Standard. Happy to help if this explanation isn't clear! https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { var-const wrote: Thanks for pointing me to the patch. It looks like this is to test an optimization that's specific to `find`. IMO we shouldn't duplicate those tests here, so I'd just remove the `Comparable` and `TriviallyComparable` tests. It might make sense to add a benchmark for `ranges::contains`, though. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libunwind] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { var-const wrote: Thanks for pointing me to the patch. It looks like this is to test an optimization that's specific to `find`. IMO we shouldn't duplicate those tests here, so I'd just remove the `Comparable` and `TriviallyComparable` tests. It might make sense to add a benchmark for `ranges::contains`, though. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { var-const wrote: Thanks for pointing me to the patch. It looks like this is to test an optimization that's specific to `find`. IMO we shouldn't duplicate those tests here, so I'd just remove the `Comparable` and `TriviallyComparable` tests. It might make sense to add a benchmark for `ranges::contains`, though. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
https://github.com/var-const unassigned https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
https://github.com/var-const unassigned https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,252 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); +static_assert(!HasContainsIt, sentinel_wrapper>>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(HasContainsIt); + +template +concept HasContainsR = requires(Range&& range) { std::ranges::contains(std::forward(range), ValT{}); }; + +static_assert(!HasContainsR); +static_assert(HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +ValueT a[] = {1, 2, 3, 4, 5, 6}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole.begin(), whole.end(), 3); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole, 3); + assert(ret); +} + } + + { // check that a range with a single element works +ValueT a[] = {32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that an empty range works +ValueT a[] = {}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 1); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 1); + assert(!ret); +} + } + + { // check that the first element matches +ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that the last element matches +ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // no match +ValueT a[] = {13, 1, 21, 4, 5}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 10); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 10); + assert(!ret); +} + } + + { // check that the projections are used +int a[] = {1, 9, 0, 13, 25}; +{ + bool ret = std::ranges::contains(a, a + 5, -13, [&](int i) { return i * -1; }); + assert(ret); +} +{ + auto range = std::ranges::subrange(a, a + 5); + bool ret = std::ranges::contains(range, -13, [&](int i) { return i * -1; }); + assert(ret); +} + } + + { // check the nodiscard extension +// use #pragma around to suppress error: ignoring return value of function +// declared with 'nodiscard' attribute [-Werror,-Wunused-result] +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-result" +ValueT a[] = {1, 9, 0, 13, 25}; +auto
[libunwind] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,252 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); +static_assert(!HasContainsIt, sentinel_wrapper>>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(HasContainsIt); + +template +concept HasContainsR = requires(Range&& range) { std::ranges::contains(std::forward(range), ValT{}); }; + +static_assert(!HasContainsR); +static_assert(HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +ValueT a[] = {1, 2, 3, 4, 5, 6}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole.begin(), whole.end(), 3); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole, 3); + assert(ret); +} + } + + { // check that a range with a single element works +ValueT a[] = {32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that an empty range works +ValueT a[] = {}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 1); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 1); + assert(!ret); +} + } + + { // check that the first element matches +ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that the last element matches +ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // no match +ValueT a[] = {13, 1, 21, 4, 5}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 10); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 10); + assert(!ret); +} + } + + { // check that the projections are used +int a[] = {1, 9, 0, 13, 25}; +{ + bool ret = std::ranges::contains(a, a + 5, -13, [&](int i) { return i * -1; }); + assert(ret); +} +{ + auto range = std::ranges::subrange(a, a + 5); + bool ret = std::ranges::contains(range, -13, [&](int i) { return i * -1; }); + assert(ret); +} + } + + { // check the nodiscard extension var-const wrote: This test should be in `libcxx/test/libcxx/diagnostics/nodiscard_extensions.compile.pass.cpp`. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,61 @@ +//===--===// +// +// 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 _LIBCPP___ALGORITHM_RANGES_CONTAINS_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_H + +#include <__algorithm/in_in_result.h> +#include <__algorithm/ranges_find.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __contains { +struct __fn { + template _Sent, class _Type, class _Proj = identity> +requires indirect_binary_predicate, const _Type*> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) const { +return ranges::find(std::move(__first), std::move(__last), __value, std::ref(__proj)) != __last; + } + + template var-const wrote: Likewise, I don't think we're testing `input_range`. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libunwind] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,252 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include var-const wrote: Nit: `` is probably no longer needed. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[libunwind] [libc++] Implement ranges::contains (PR #65148)
https://github.com/var-const unassigned https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
https://github.com/var-const requested changes to this pull request. Thanks for addressing most of the feedback! Did another round. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,252 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); +static_assert(!HasContainsIt, sentinel_wrapper>>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(HasContainsIt); + +template +concept HasContainsR = requires(Range&& range) { std::ranges::contains(std::forward(range), ValT{}); }; + +static_assert(!HasContainsR); +static_assert(HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +ValueT a[] = {1, 2, 3, 4, 5, 6}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole.begin(), whole.end(), 3); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole, 3); + assert(ret); +} + } + + { // check that a range with a single element works +ValueT a[] = {32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that an empty range works +ValueT a[] = {}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 1); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 1); + assert(!ret); +} + } + + { // check that the first element matches +ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that the last element matches +ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // no match +ValueT a[] = {13, 1, 21, 4, 5}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 10); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 10); + assert(!ret); +} + } + + { // check that the projections are used +int a[] = {1, 9, 0, 13, 25}; +{ + bool ret = std::ranges::contains(a, a + 5, -13, [&](int i) { return i * -1; }); + assert(ret); +} +{ + auto range = std::ranges::subrange(a, a + 5); + bool ret = std::ranges::contains(range, -13, [&](int i) { return i * -1; }); + assert(ret); +} + } + + { // check the nodiscard extension +// use #pragma around to suppress error: ignoring return value of function +// declared with 'nodiscard' attribute [-Werror,-Wunused-result] +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-result" +ValueT a[] = {1, 9, 0, 13, 25}; +auto
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,252 @@ +//===--===// var-const wrote: Can you please go through various `robust` test files and add tests for `contains` where it makes sense? Let me know if you need any help with that! https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,252 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include var-const wrote: Nit: `` is probably no longer needed. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,252 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); +static_assert(!HasContainsIt, sentinel_wrapper>>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(HasContainsIt); + +template +concept HasContainsR = requires(Range&& range) { std::ranges::contains(std::forward(range), ValT{}); }; + +static_assert(!HasContainsR); +static_assert(HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +ValueT a[] = {1, 2, 3, 4, 5, 6}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole.begin(), whole.end(), 3); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole, 3); + assert(ret); +} + } + + { // check that a range with a single element works +ValueT a[] = {32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that an empty range works +ValueT a[] = {}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 1); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 1); + assert(!ret); +} + } + + { // check that the first element matches +ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that the last element matches +ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // no match +ValueT a[] = {13, 1, 21, 4, 5}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 10); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 10); + assert(!ret); +} + } + + { // check that the projections are used +int a[] = {1, 9, 0, 13, 25}; +{ + bool ret = std::ranges::contains(a, a + 5, -13, [&](int i) { return i * -1; }); + assert(ret); +} +{ + auto range = std::ranges::subrange(a, a + 5); + bool ret = std::ranges::contains(range, -13, [&](int i) { return i * -1; }); + assert(ret); +} + } + + { // check the nodiscard extension var-const wrote: This test should be in `libcxx/test/libcxx/diagnostics/nodiscard_extensions.compile.pass.cpp`. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org
[libunwind] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,61 @@ +//===--===// +// +// 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 _LIBCPP___ALGORITHM_RANGES_CONTAINS_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_H + +#include <__algorithm/in_in_result.h> +#include <__algorithm/ranges_find.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __contains { +struct __fn { + template _Sent, class _Type, class _Proj = identity> +requires indirect_binary_predicate, const _Type*> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) const { +return ranges::find(std::move(__first), std::move(__last), __value, std::ref(__proj)) != __last; + } + + template +requires indirect_binary_predicate, _Proj>, const _Type*> + _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Range&& __range, const _Type& __value, _Proj __proj = {}) const { +return ranges::find(ranges::begin(__range), ranges::end(__range), __value, std::ref(__proj)) != ranges::end(__range); var-const wrote: Nit: I think this line is a little over the max width. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,252 @@ +//===--===// +// +// 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, c++20 + +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); +static_assert(!HasContainsIt, sentinel_wrapper>>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(HasContainsIt); + +template +concept HasContainsR = requires(Range&& range) { std::ranges::contains(std::forward(range), ValT{}); }; + +static_assert(!HasContainsR); +static_assert(HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +ValueT a[] = {1, 2, 3, 4, 5, 6}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole.begin(), whole.end(), 3); + assert(ret); +} +{ + [[maybe_unused]] std::same_as decltype(auto) ret = +std::ranges::contains(whole, 3); + assert(ret); +} + } + + { // check that a range with a single element works +ValueT a[] = {32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 1))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that an empty range works +ValueT a[] = {}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 1); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 1); + assert(!ret); +} + } + + { // check that the first element matches +ValueT a[] = {32, 3, 2, 1, 0, 23, 21, 9, 40, 100}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 10))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // check that the last element matches +ValueT a[] = {3, 22, 1, 43, 99, 0, 56, 100, 32}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 9))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 32); + assert(ret); +} +{ + bool ret = std::ranges::contains(whole, 32); + assert(ret); +} + } + + { // no match +ValueT a[] = {13, 1, 21, 4, 5}; +auto whole = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); +{ + bool ret = std::ranges::contains(whole.begin(), whole.end(), 10); + assert(!ret); +} +{ + bool ret = std::ranges::contains(whole, 10); + assert(!ret); +} + } + + { // check that the projections are used +int a[] = {1, 9, 0, 13, 25}; +{ + bool ret = std::ranges::contains(a, a + 5, -13, [&](int i) { return i * -1; }); + assert(ret); +} +{ + auto range = std::ranges::subrange(a, a + 5); + bool ret = std::ranges::contains(range, -13, [&](int i) { return i * -1; }); + assert(ret); +} + } + + { // check the nodiscard extension +// use #pragma around to suppress error: ignoring return value of function +// declared with 'nodiscard' attribute [-Werror,-Wunused-result] +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-result" +ValueT a[] = {1, 9, 0, 13, 25}; +auto
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; var-const wrote: @EricWF I think it's just conceptually simpler. Consider: ```cpp // A { int input[] = {5, 7, 8, 13, 3, 6}; assert(ranges::contains(in, in + std::size(in), 3)); } { int input[] = {48, 16, 32, 45, 99, 128, 37, 64, 15}; assert(ranges::contains(in, 64)); } // B { int input[] = {5, 7, 8, 13, 3, 6}; assert(ranges::contains(in, in + std::size(in), 3)); } { int input[] = {5, 7, 8, 13, 3, 6}; assert(ranges::contains(in, 3)); } // C int input[] = {5, 7, 8, 13, 3, 6}; { assert(ranges::contains(in, in + std::size(in), 3)); } { assert(ranges::contains(in, 3)); } ``` IMO while `A` is valid, it's overly complicated for no reason -- now the reader has to examine both input sequences to understand (or verify) what the test is doing. `B` is better because now there is no unnecessary divergence, but there is still some overhead to see if the sequences are the same or not. `C` removes that overhead, however small, and also most directly conveys the underlying idea (we are running equivalent tests on the two overloads of the function). The fact that it reduces the line count is also nice but not the primary motivation. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; var-const wrote: @EricWF I think it's just conceptually simpler. Consider: ```cpp // A { int input[] = {5, 7, 8, 13, 3, 6}; assert(ranges::contains(in, in + std::size(in), 3)); } { int input[] = {48, 16, 32, 45, 99, 128, 37, 64, 15}; assert(ranges::contains(in, 64)); } // B { int input[] = {5, 7, 8, 13, 3, 6}; assert(ranges::contains(in, in + std::size(in), 3)); } { int input[] = {5, 7, 8, 13, 3, 6}; assert(ranges::contains(in, 3)); } // C int input[] = {5, 7, 8, 13, 3, 6}; { assert(ranges::contains(in, in + std::size(in), 3)); } { assert(ranges::contains(in, 3)); } ``` IMO while `A` is valid, it's overly complicated for no reason -- now the reader has to examine both input sequences to understand (or verify) what the test is doing. `B` is better because now there is no unnecessary divergence, but there is still some overhead to see if the sequences are the same or not. `C` removes that overhead, however small, and also most directly conveys the underlying idea (we are running equivalent tests on the two overloads of the function). The fact that it reduces the line count is also nice but not the primary motivation. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { + ElementT el_; + +public: + TEST_CONSTEXPR TriviallyComparable(ElementT el) : el_(el) {} + bool operator==(const TriviallyComparable&) const = default; var-const wrote: You're right, disregard the comment. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { + ElementT el_; + +public: + TEST_CONSTEXPR TriviallyComparable(ElementT el) : el_(el) {} + bool operator==(const TriviallyComparable&) const = default; var-const wrote: You're right, disregard the comment. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); var-const wrote: Personally, I think using a built-in is a little more elegant -- it avoids the question of which container to use and also adding an include that is only used once. But I don't mean to imply that we should strongly avoid using `std::array` or anything like that, so I marked my comment "optional". https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); var-const wrote: Personally, I think using a built-in is a little more elegant -- it avoids the question of which container to use and also adding an include that is only used once. But I don't mean to imply that we should strongly avoid using `std::array` or anything like that, so I marked my comment "optional". https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { + ElementT el_; + +public: + TEST_CONSTEXPR TriviallyComparable(ElementT el) : el_(el) {} var-const wrote: `TEST_CONSTEXPR` is a compatibility macro -- it exists for tests that need to compile in C++03 mode so that we can optionally mark something as `constexpr` (the macro would expand to `constexpr` in C++11 and later and to nothing in C++03 mode so that the test won't fail to compile). Since this test requires C++23 or above, you can just use `constexpr`. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { + ElementT el_; + +public: + TEST_CONSTEXPR TriviallyComparable(ElementT el) : el_(el) {} + bool operator==(const TriviallyComparable&) const = default; var-const wrote: Shouldn't this function be `constexpr` as well? https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match var-const wrote: We can also check: - one-element range; - the match is the very first element; - the match is the last element. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off var-const wrote: Question: what's the reason to turn off `clang-format`? We generally try to make sections where formatting is turned off as short as possible (i.e., only to work around some specific problems where it produces broken formatting, or sometimes to allow manual fancy formatting for e.g. a large initializer). https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); var-const wrote: Same here -- can you also test `static_assert(!HasContainsIt);`? https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { var-const wrote: Note: it's easy to presume that "trivially" in this context means that the type can be compared using `memcmp` (we have an internal trait `__libcpp_is_trivially_equality_comparable` and there are in-progress proposals to provide a "trivially comparable" type trait, similar to "trivially copyable" and the like). I don't think that's the intended meaning here, so I'd remove or replace that word. What is the purpose of this class? To test user-defined comparison operators? https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} var-const wrote: Nit: please add a blank line after this line (to separate this function from the helper class). https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); var-const wrote: To make sure the concept works as expected, can you also test the successful case? ```cpp static_assert(!HasContainsIt, sentinel_wrapper>); ``` https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); var-const wrote: I think using `comparable_data` is not necessary (see comment below), but apart from that, it's an implementation detail of `Comparable` and ideally the `test_iterators` function shouldn't be aware of it. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); var-const wrote: Same here -- can you also test `static_assert(!HasContainsIt);`? https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a + 5)), 10); + assert(!ret); +} +{ + ValueT a[] = {13, 1, 21, 4, 5}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 5))); + auto ret = std::ranges::contains(range, 10); + assert(!ret); +} + } + + if (!std::is_constant_evaluated()) +comparable_data.clear(); +} +template +class TriviallyComparable { + ElementT el_; + +public: + TEST_CONSTEXPR TriviallyComparable(ElementT el) : el_(el) {} var-const wrote: `TEST_CONSTEXPR` is a compatibility macro -- it exists for tests that need to compile in C++03 mode so that we can optionally mark something as `constexpr` (the macro would expand to `constexpr` in C++11 and later and to nothing in C++03 mode so that the test won't fail to compile). Since this test requires C++23 or above, you can just use `constexpr`. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; + +static_assert(HasContainsR, int>); +static_assert(!HasContainsR); +static_assert(!HasContainsR, NotEqualityComparable>); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); +static_assert(!HasContainsR); + +static std::vector comparable_data; + +// clang-format off +template +constexpr void test_iterators() { + using ValueT = std::iter_value_t; + { // simple tests +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + std::same_as auto ret = +std::ranges::contains(Iter(a), Sent(Iter(a + 6)), 3); + assert(ret); +} +{ + ValueT a[] = {1, 2, 3, 4, 5, 6}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 6))); + std::same_as decltype(auto) ret = +std::ranges::contains(range, 3); + assert(ret); +} + } + + { // check that an empty range works +{ + ValueT a[] = {}; + auto ret = std::ranges::contains(Iter(a), Sent(Iter(a)), 1); + assert(!ret); +} +{ + ValueT a[] = {}; + auto range = std::ranges::subrange(Iter(a), Sent(Iter(a))); + auto ret = std::ranges::contains(range, 1); + assert(!ret); +} + } + + { // check that no match var-const wrote: Nit: either `s/check that no match/no match/` or `s/check that no match/check the case when there's no match/`. https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [libc++] Implement ranges::contains (PR #65148)
@@ -0,0 +1,190 @@ +//===--===// +// +// 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, c++20 +// template S, class T, class Proj = identity> +// requires indirect_binary_predicate, const T*> +// constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); // since C++23 + +// template +// requires indirect_binary_predicate, Proj>, const T*> +// constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); // since C++23 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +struct NotEqualityComparable {}; + +template +concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); }; + +static_assert(HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); +static_assert(!HasContainsIt, SentinelForNotSemiregular>); +static_assert(!HasContainsIt, InputRangeNotSentinelEqualityComparableWith>); + +static_assert(!HasContainsIt); +static_assert(!HasContainsIt); + +template +concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); }; var-const wrote: Nit: I'd suggest accepting the argument by a forwarding reference then calling `std::forward` on it when passing it to `contains` (that way it's more similar to how calling `contains` directly would work). https://github.com/llvm/llvm-project/pull/65148 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits