[clang] b198f16 - [Analyzer] Model STL Algoirthms to improve the iterator checkers

Adam Balogh via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 5 08:55:59 PST 2020


Author: Adam Balogh
Date: 2020-02-05T17:59:08+01:00
New Revision: b198f16e1e1c8ee849008c1b886199eae5bc2e01

URL: https://github.com/llvm/llvm-project/commit/b198f16e1e1c8ee849008c1b886199eae5bc2e01
DIFF: https://github.com/llvm/llvm-project/commit/b198f16e1e1c8ee849008c1b886199eae5bc2e01.diff

LOG: [Analyzer] Model STL Algoirthms to improve the iterator checkers

STL Algorithms are usually implemented in a tricky for performance
reasons which is too complicated for the analyzer. Furthermore inlining
them is costly. Instead of inlining we should model their behavior
according to the specifications.

This patch is the first step towards STL Algorithm modeling. It models
all the `find()`-like functions in a simple way: the result is either
found or not. In the future it can be extended to only return success if
container modeling is also extended in a way the it keeps track of
trivial insertions and deletions.

Differential Revision: https://reviews.llvm.org/D70818

Added: 
    clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
    clang/test/Analysis/stl-algorithm-modeling-aggressive-std-find-modeling.cpp
    clang/test/Analysis/stl-algorithm-modeling.cpp

Modified: 
    clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
    clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
    clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
    clang/lib/StaticAnalyzer/Checkers/Iterator.h
    clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
    clang/test/Analysis/Inputs/system-header-simulator-cxx.h
    clang/test/Analysis/analyzer-config.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 6a7fbfe83041..50610de6843e 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -622,6 +622,19 @@ def IteratorModeling : Checker<"IteratorModeling">,
   Documentation<NotDocumented>,
   Hidden;
 
+def STLAlgorithmModeling : Checker<"STLAlgorithmModeling">,
+  HelpText<"Models the algorithm library of the C++ STL.">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "AggressiveStdFindModeling",
+                  "Enables exploration of the failure branch in std::find-like "
+                  "functions.",
+                  "false",
+                  Released>
+  ]>,
+  Dependencies<[ContainerModeling]>,
+  Documentation<NotDocumented>;
+
 def InvalidatedIteratorChecker : Checker<"InvalidatedIterator">,
   HelpText<"Check for use of invalidated iterators">,
   Dependencies<[IteratorModeling]>,

diff  --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index b6af13d4e97f..765c2f3e4530 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -99,6 +99,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   SmartPtrModeling.cpp
   StackAddrEscapeChecker.cpp
   StdLibraryFunctionsChecker.cpp
+  STLAlgorithmModeling.cpp
   StreamChecker.cpp
   Taint.cpp
   TaintTesterChecker.cpp

diff  --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
index 612d3050babd..64daf358fbe5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
@@ -177,6 +177,20 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
   return nullptr;
 }
 
+ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
+                                       const MemRegion *Cont, const Stmt* S,
+                                       const LocationContext *LCtx,
+                                       unsigned blockCount) {
+  auto &StateMgr = State->getStateManager();
+  auto &SymMgr = StateMgr.getSymbolManager();
+  auto &ACtx = StateMgr.getContext();
+
+  auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount);
+  State = assumeNoOverflow(State, Sym, 4);
+  return setIteratorPosition(State, Val,
+                             IteratorPosition::getPosition(Cont, Sym));
+}
+
 ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter,
                                 OverloadedOperatorKind Op,
                                 const SVal &Distance) {

diff  --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.h b/clang/lib/StaticAnalyzer/Checkers/Iterator.h
index a1a24732794b..d5c6cb96ebc6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Iterator.h
+++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h
@@ -159,6 +159,10 @@ const IteratorPosition *getIteratorPosition(ProgramStateRef State,
                                             const SVal &Val);
 ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
                                     const IteratorPosition &Pos);
+ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
+                                       const MemRegion *Cont, const Stmt* S,
+                                       const LocationContext *LCtx,
+                                       unsigned blockCount);
 ProgramStateRef advancePosition(ProgramStateRef State,
                                 const SVal &Iter,
                                 OverloadedOperatorKind Op,

diff  --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index 997d492a8e58..955a40b0d4b7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -487,12 +487,9 @@ void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
   Cont = Cont->getMostDerivedObjectRegion();
 
   auto State = C.getState();
-  auto &SymMgr = C.getSymbolManager();
-  auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
-                                  C.getASTContext().LongTy, C.blockCount());
-  State = assumeNoOverflow(State, Sym, 4);
-  State = setIteratorPosition(State, RetVal,
-                              IteratorPosition::getPosition(Cont, Sym));
+  const auto *LCtx = C.getLocationContext();
+  State = createIteratorPosition(State, RetVal, Cont, CE, LCtx, C.blockCount());
+
   C.addTransition(State);
 }
 

diff  --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
new file mode 100644
index 000000000000..9452ccdc46c9
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -0,0 +1,180 @@
+//===-- STLAlgorithmModeling.cpp -----------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Models STL algorithms.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+#include "Iterator.h"
+
+using namespace clang;
+using namespace ento;
+using namespace iterator;
+
+namespace {
+
+class STLAlgorithmModeling : public Checker<eval::Call> {
+  bool evalFind(CheckerContext &C, const CallExpr *CE) const;
+
+  void Find(CheckerContext &C, const CallExpr *CE, unsigned paramNum) const;
+
+  using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &,
+                                                const CallExpr *) const;
+
+  const CallDescriptionMap<FnCheck> Callbacks = {
+    {{{"std", "find"}, 3}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_if"}, 3}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_if"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_if_not"}, 3}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_if_not"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_first_of"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_first_of"}, 5}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_first_of"}, 6}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_end"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_end"}, 5}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "find_end"}, 6}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "lower_bound"}, 3}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "lower_bound"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "upper_bound"}, 3}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "upper_bound"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "search"}, 3}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "search"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "search"}, 5}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "search"}, 6}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "search_n"}, 4}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "search_n"}, 5}, &STLAlgorithmModeling::evalFind},
+    {{{"std", "search_n"}, 6}, &STLAlgorithmModeling::evalFind},
+  };
+
+public:
+  STLAlgorithmModeling() = default;
+
+  bool AggressiveStdFindModeling;
+
+  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+}; //
+
+bool STLAlgorithmModeling::evalCall(const CallEvent &Call,
+                                    CheckerContext &C) const {
+  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+  if (!CE)
+    return false;
+
+  const FnCheck *Handler = Callbacks.lookup(Call);
+  if (!Handler)
+    return false;
+
+  return (this->**Handler)(C, CE);
+}
+
+bool STLAlgorithmModeling::evalFind(CheckerContext &C,
+                                    const CallExpr *CE) const {
+  // std::find()-like functions either take their primary range in the first
+  // two parameters, or if the first parameter is "execution policy" then in
+  // the second and third. This means that the second parameter must always be
+  // an iterator.
+  if (!isIteratorType(CE->getArg(1)->getType()))
+    return false;
+
+  // If no "execution policy" parameter is used then the first argument is the
+  // beginning of the range.
+  if (isIteratorType(CE->getArg(0)->getType())) {
+    Find(C, CE, 0);
+    return true;
+  }
+
+  // If "execution policy" parameter is used then the second argument is the
+  // beginning of the range.
+  if (isIteratorType(CE->getArg(2)->getType())) {
+    Find(C, CE, 1);
+    return true;
+  }
+
+  return false;
+}
+
+void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
+                                unsigned paramNum) const {
+  auto State = C.getState();
+  auto &SVB = C.getSValBuilder();
+  const auto *LCtx = C.getLocationContext();
+
+  SVal RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
+  SVal Param = State->getSVal(CE->getArg(paramNum), LCtx);
+
+  auto StateFound = State->BindExpr(CE, LCtx, RetVal);
+
+  // If we have an iterator position for the range-begin argument then we can
+  // assume that in case of successful search the position of the found element
+  // is not ahead of it.
+  // FIXME: Reverse iterators
+  const auto *Pos = getIteratorPosition(State, Param);
+  if (Pos) {
+    StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
+                                        CE, LCtx, C.blockCount());
+    const auto *NewPos = getIteratorPosition(StateFound, RetVal);
+    assert(NewPos && "Failed to create new iterator position.");
+
+    SVal GreaterOrEqual = SVB.evalBinOp(StateFound, BO_GE,
+                                        nonloc::SymbolVal(NewPos->getOffset()),
+                                        nonloc::SymbolVal(Pos->getOffset()),
+                                        SVB.getConditionType());
+    assert(GreaterOrEqual.getAs<DefinedSVal>() &&
+           "Symbol comparison must be a `DefinedSVal`");
+    StateFound = StateFound->assume(GreaterOrEqual.castAs<DefinedSVal>(), true);
+  }
+
+  Param = State->getSVal(CE->getArg(paramNum + 1), LCtx);
+
+  // If we have an iterator position for the range-end argument then we can
+  // assume that in case of successful search the position of the found element
+  // is ahead of it.
+  // FIXME: Reverse iterators
+  Pos = getIteratorPosition(State, Param);
+  if (Pos) {
+    StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
+                                        CE, LCtx, C.blockCount());
+    const auto *NewPos = getIteratorPosition(StateFound, RetVal);
+    assert(NewPos && "Failed to create new iterator position.");
+
+    SVal Less = SVB.evalBinOp(StateFound, BO_LT,
+                              nonloc::SymbolVal(NewPos->getOffset()),
+                              nonloc::SymbolVal(Pos->getOffset()),
+                              SVB.getConditionType());
+    assert(Less.getAs<DefinedSVal>() &&
+           "Symbol comparison must be a `DefinedSVal`");
+    StateFound = StateFound->assume(Less.castAs<DefinedSVal>(), true);
+  }
+
+  C.addTransition(StateFound);
+
+  if (AggressiveStdFindModeling) {
+    auto StateNotFound = State->BindExpr(CE, LCtx, Param);
+    C.addTransition(StateNotFound);
+  }
+}
+
+} // namespace
+
+void ento::registerSTLAlgorithmModeling(CheckerManager &Mgr) {
+  auto *Checker = Mgr.registerChecker<STLAlgorithmModeling>();
+  Checker->AggressiveStdFindModeling =
+      Mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker,
+                                                  "AggressiveStdFindModeling");
+}
+
+bool ento::shouldRegisterSTLAlgorithmModeling(const LangOptions &LO) {
+  return true;
+}
+

diff  --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
index 77b87627f6e3..54cfdcef7b16 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -783,14 +783,121 @@ namespace std {
     return it;
   }
 
-  template <class InputIterator, class T>
-  InputIterator find(InputIterator first, InputIterator last, const T &val);
-
-  template <class ForwardIterator1, class ForwardIterator2>
-  ForwardIterator1 find_first_of(ForwardIterator1 first1,
-                                 ForwardIterator1 last1,
-                                 ForwardIterator2 first2,
-                                 ForwardIterator2 last2);
+  template <class InputIt, class T>
+  InputIt find(InputIt first, InputIt last, const T& value);
+
+  template <class ExecutionPolicy, class ForwardIt, class T>
+  ForwardIt find(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
+                 const T& value);
+
+  template <class InputIt, class UnaryPredicate>
+  InputIt find_if (InputIt first, InputIt last, UnaryPredicate p);
+
+  template <class ExecutionPolicy, class ForwardIt, class UnaryPredicate>
+  ForwardIt find_if (ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
+                     UnaryPredicate p);
+
+  template <class InputIt, class UnaryPredicate>
+  InputIt find_if_not (InputIt first, InputIt last, UnaryPredicate q);
+
+  template <class ExecutionPolicy, class ForwardIt, class UnaryPredicate>
+  ForwardIt find_if_not (ExecutionPolicy&& policy, ForwardIt first,
+                         ForwardIt last, UnaryPredicate q);
+
+  template <class InputIt, class ForwardIt>
+  InputIt find_first_of(InputIt first, InputIt last,
+                         ForwardIt s_first, ForwardIt s_last);
+
+  template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
+  ForwardIt1 find_first_of (ExecutionPolicy&& policy,
+                            ForwardIt1 first, ForwardIt1 last,
+                            ForwardIt2 s_first, ForwardIt2 s_last);
+
+  template <class InputIt, class ForwardIt, class BinaryPredicate>
+  InputIt find_first_of (InputIt first, InputIt last,
+                         ForwardIt s_first, ForwardIt s_last,
+                         BinaryPredicate p );
+
+  template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
+            class BinaryPredicate>
+  ForwardIt1 find_first_of (ExecutionPolicy&& policy,
+                            ForwardIt1 first, ForwardIt1 last,
+                            ForwardIt2 s_first, ForwardIt2 s_last,
+                            BinaryPredicate p );
+
+  template <class InputIt, class ForwardIt>
+  InputIt find_end(InputIt first, InputIt last,
+                   ForwardIt s_first, ForwardIt s_last);
+
+  template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
+  ForwardIt1 find_end (ExecutionPolicy&& policy,
+                       ForwardIt1 first, ForwardIt1 last,
+                       ForwardIt2 s_first, ForwardIt2 s_last);
+
+  template <class InputIt, class ForwardIt, class BinaryPredicate>
+  InputIt find_end (InputIt first, InputIt last,
+                    ForwardIt s_first, ForwardIt s_last,
+                    BinaryPredicate p );
+
+  template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
+            class BinaryPredicate>
+  ForwardIt1 find_end (ExecutionPolicy&& policy,
+                       ForwardIt1 first, ForwardIt1 last,
+                       ForwardIt2 s_first, ForwardIt2 s_last,
+                       BinaryPredicate p );
+
+  template <class ForwardIt, class T>
+  ForwardIt lower_bound (ForwardIt first, ForwardIt last, const T& value);
+
+  template <class ForwardIt, class T, class Compare>
+  ForwardIt lower_bound (ForwardIt first, ForwardIt last, const T& value,
+                         Compare comp);
+
+  template <class ForwardIt, class T>
+  ForwardIt upper_bound (ForwardIt first, ForwardIt last, const T& value);
+
+  template <class ForwardIt, class T, class Compare>
+  ForwardIt upper_bound (ForwardIt first, ForwardIt last, const T& value,
+                         Compare comp);
+
+  template <class ForwardIt1, class ForwardIt2>
+  ForwardIt1 search (ForwardIt1 first, ForwardIt1 last,
+                     ForwardIt2 s_first, ForwardIt2 s_last);
+
+  template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
+  ForwardIt1 search (ExecutionPolicy&& policy,
+                     ForwardIt1 first, ForwardIt1 last,
+                     ForwardIt2 s_first, ForwardIt2 s_last);
+
+  template <class ForwardIt1, class ForwardIt2, class BinaryPredicate>
+  ForwardIt1 search (ForwardIt1 first, ForwardIt1 last,
+                     ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p);
+
+  template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
+            class BinaryPredicate >
+  ForwardIt1 search (ExecutionPolicy&& policy,
+                     ForwardIt1 first, ForwardIt1 last,
+                     ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p);
+
+  template <class ForwardIt, class Searcher>
+  ForwardIt search (ForwardIt first, ForwardIt last, const Searcher& searcher);
+
+  template <class ForwardIt, class Size, class T>
+  ForwardIt search_n (ForwardIt first, ForwardIt last, Size count,
+                      const T& value);
+
+  template <class ExecutionPolicy, class ForwardIt, class Size, class T>
+  ForwardIt search_n (ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
+                      Size count, const T& value);
+
+  template <class ForwardIt, class Size, class T, class BinaryPredicate>
+  ForwardIt search_n (ForwardIt first, ForwardIt last, Size count,
+                      const T& value, BinaryPredicate p);
+
+  template <class ExecutionPolicy, class ForwardIt, class Size, class T,
+            class BinaryPredicate>
+  ForwardIt search_n (ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
+                      Size count, const T& value, BinaryPredicate p);
 
   template <class InputIterator, class OutputIterator>
   OutputIterator copy(InputIterator first, InputIterator last,
@@ -927,4 +1034,22 @@ template<
     iterator begin() const { return iterator(val); }
     iterator end() const { return iterator(val + 1); }
 };
+
+namespace execution {
+class sequenced_policy {};
+}
+
+template <class T = void> struct equal_to {};
+
+template <class ForwardIt, class BinaryPredicate = std::equal_to<> >
+class default_searcher {
+public:
+  default_searcher (ForwardIt pat_first,
+                    ForwardIt pat_last,
+                    BinaryPredicate pred = BinaryPredicate());
+  template <class ForwardIt2>
+  std::pair <ForwardIt2, ForwardIt2>
+  operator()( ForwardIt2 first, ForwardIt2 last ) const;
+};
+
 }

diff  --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index 4707da3b9a3a..5b0566d5a820 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -7,6 +7,7 @@
 // CHECK-NEXT: alpha.clone.CloneChecker:IgnoredFilesPattern = ""
 // CHECK-NEXT: alpha.clone.CloneChecker:MinimumCloneComplexity = 50
 // CHECK-NEXT: alpha.clone.CloneChecker:ReportNormalClones = true
+// CHECK-NEXT: alpha.cplusplus.STLAlgorithmModeling:AggressiveStdFindModeling = false
 // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtExec = 0x04
 // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtRead = 0x01
 // CHECK-NEXT: alpha.security.taint.TaintPropagation:Config = ""
@@ -99,4 +100,4 @@
 // CHECK-NEXT: unroll-loops = false
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 96
+// CHECK-NEXT: num-entries = 97

diff  --git a/clang/test/Analysis/stl-algorithm-modeling-aggressive-std-find-modeling.cpp b/clang/test/Analysis/stl-algorithm-modeling-aggressive-std-find-modeling.cpp
new file mode 100644
index 000000000000..98301cf7274f
--- /dev/null
+++ b/clang/test/Analysis/stl-algorithm-modeling-aggressive-std-find-modeling.cpp
@@ -0,0 +1,620 @@
+// RUN: %clang_analyze_cc1 -std=c++17 %s\
+// RUN:  -analyzer-checker=core,cplusplus,alpha.cplusplus.STLAlgorithmModeling,debug.DebugIteratorModeling,debug.ExprInspection\
+// RUN:  -analyzer-config aggressive-binary-operation-simplification=true\
+// RUN:  -analyzer-config alpha.cplusplus.STLAlgorithmModeling:AggressiveStdFindModeling=true\
+// RUN:  -verify
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void clang_analyzer_eval(bool);
+
+template <typename Iterator>
+long clang_analyzer_iterator_position(const Iterator&);
+
+template <typename Iter> Iter return_any_iterator(const Iter &It);
+
+void test_find1(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find(i1, i2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find2(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find(std::execution::sequenced_policy(), i1, i2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+bool odd(int i) { return i % 2; }
+
+void test_find_if1(std::vector<int> V) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find_if(i1, i2, odd);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_if2(std::vector<int> V) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find_if(std::execution::sequenced_policy(), i1, i2, odd);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_if_not1(std::vector<int> V) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find_if_not(i1, i2, odd);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_if_not2(std::vector<int> V) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find_if_not(std::execution::sequenced_policy(), i1, i2,
+                                   odd);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_first_of1(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_first_of(i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_first_of2(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_first_of(std::execution::sequenced_policy(),
+                                     i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_first_of3(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_first_of(i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_first_of4(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_first_of(std::execution::sequenced_policy(),
+                                     i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_end1(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_end(i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_end2(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_end(std::execution::sequenced_policy(),
+                                i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_end3(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_end(i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_find_end4(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_end(std::execution::sequenced_policy(),
+                                i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+bool compare(int, int);
+
+void test_lower_bound1(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::lower_bound(i1, i2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_lower_bound2(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::lower_bound(i1, i2, n, compare);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_upper_bound1(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::upper_bound(i1, i2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_upper_bound2(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::upper_bound(i1, i2, n, compare);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search1(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search2(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(std::execution::sequenced_policy(),
+                              i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search3(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search4(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(std::execution::sequenced_policy(),
+                              i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search5(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(i1, i2, std::default_searcher(i3, i4));
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i5 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search_n1(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::search_n(i1, i2, 2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search_n2(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::search_n(std::execution::sequenced_policy(),
+                                i1, i2, 2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search_n3(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::search_n(i1, i2, 2, n, compare);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}
+
+void test_search_n4(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::search_n(std::execution::sequenced_policy(),
+                                i1, i2, 2, n, compare);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+
+  if (i3 != i2) {
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+    clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                        clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+  }
+}

diff  --git a/clang/test/Analysis/stl-algorithm-modeling.cpp b/clang/test/Analysis/stl-algorithm-modeling.cpp
new file mode 100644
index 000000000000..5549c24a8c22
--- /dev/null
+++ b/clang/test/Analysis/stl-algorithm-modeling.cpp
@@ -0,0 +1,566 @@
+// RUN: %clang_analyze_cc1 -std=c++17 %s\
+// RUN:  -analyzer-checker=core,cplusplus,alpha.cplusplus.STLAlgorithmModeling,debug.DebugIteratorModeling,debug.ExprInspection\
+// RUN:  -analyzer-config aggressive-binary-operation-simplification=true\
+// RUN:  -verify
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void clang_analyzer_eval(bool);
+
+template <typename Iterator>
+long clang_analyzer_iterator_position(const Iterator&);
+
+template <typename Iter> Iter return_any_iterator(const Iter &It);
+
+void test_find1(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find(i1, i2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find2(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find(std::execution::sequenced_policy(), i1, i2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+bool odd(int i) { return i % 2; }
+
+void test_find_if1(std::vector<int> V) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find_if(i1, i2, odd);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_if2(std::vector<int> V) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find_if(std::execution::sequenced_policy(), i1, i2, odd);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_if_not1(std::vector<int> V) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find_if_not(i1, i2, odd);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_if_not2(std::vector<int> V) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::find_if_not(std::execution::sequenced_policy(), i1, i2,
+                                   odd);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_first_of1(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_first_of(i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_first_of2(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_first_of(std::execution::sequenced_policy(),
+                                     i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_first_of3(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_first_of(i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_first_of4(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_first_of(std::execution::sequenced_policy(),
+                                     i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_end1(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_end(i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_end2(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_end(std::execution::sequenced_policy(),
+                                i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_end3(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_end(i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_find_end4(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::find_end(std::execution::sequenced_policy(),
+                                i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+bool compare(int, int);
+
+void test_lower_bound1(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::lower_bound(i1, i2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_lower_bound2(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::lower_bound(i1, i2, n, compare);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_upper_bound1(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::upper_bound(i1, i2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_upper_bound2(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::upper_bound(i1, i2, n, compare);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search1(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search2(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(std::execution::sequenced_policy(),
+                              i1, i2, i3, i4);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search3(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search4(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(std::execution::sequenced_policy(),
+                              i1, i2, i3, i4, odd);
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search5(std::vector<int> V1, std::vector<int> V2) {
+  const auto i1 = return_any_iterator(V1.begin());
+  const auto i2 = return_any_iterator(V1.begin());
+  const auto i3 = return_any_iterator(V2.begin());
+  const auto i4 = return_any_iterator(V2.begin());
+
+  const auto i5 = std::search(i1, i2, std::default_searcher(i3, i4));
+
+  clang_analyzer_eval(i5 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i5) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search_n1(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::search_n(i1, i2, 2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search_n2(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::search_n(std::execution::sequenced_policy(),
+                                i1, i2, 2, n);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search_n3(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::search_n(i1, i2, 2, n, compare);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}
+
+void test_search_n4(std::vector<int> V, int n) {
+  const auto i1 = return_any_iterator(V.begin());
+  const auto i2 = return_any_iterator(V.begin());
+
+  const auto i3 = std::search_n(std::execution::sequenced_policy(),
+                                i1, i2, 2, n, compare);
+
+  clang_analyzer_eval(i3 == i2); // expected-warning{{FALSE}}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i1)); // expected-warning at -1{{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) <
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(i3) >=
+                      clang_analyzer_iterator_position(i2)); // expected-warning at -1{{FALSE}}
+}


        


More information about the cfe-commits mailing list