[clang] Add option -fstdlib-hardening= (PR #78763)

2024-01-30 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-30 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-26 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-26 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-26 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2024-01-25 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2024-01-25 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2024-01-25 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-25 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-22 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2024-01-21 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-20 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-20 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-20 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-20 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-20 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-20 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-20 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-19 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-19 Thread Konstantin Varlamov via cfe-commits

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)

2024-01-19 Thread Konstantin Varlamov via cfe-commits

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)

2023-12-21 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits

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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits

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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits

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)

2023-12-20 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-18 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-14 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-14 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-14 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-12 Thread Konstantin Varlamov via cfe-commits

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)

2023-12-12 Thread Konstantin Varlamov via cfe-commits

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)

2023-12-12 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-12 Thread Konstantin Varlamov via cfe-commits

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)

2023-12-12 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-12-12 Thread Konstantin Varlamov via cfe-commits

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)

2023-11-08 Thread Konstantin Varlamov via cfe-commits

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)

2023-11-08 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-13 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-03 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-03 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-03 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits

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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-10-02 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-07 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-07 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-07 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-07 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-07 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-07 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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)

2023-09-01 Thread Konstantin Varlamov via cfe-commits


@@ -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


  1   2   >