diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -622,6 +622,19 @@ Documentation, Hidden; +def STLAlgorithmModeling : Checker<"STLAlgorithmModeling">, + HelpText<"Models the algorithm library of the C++ STL.">, + CheckerOptions<[ + CmdLineOption + ]>, + Dependencies<[ContainerModeling]>, + Documentation; + 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 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -99,6 +99,7 @@ SmartPtrModeling.cpp StackAddrEscapeChecker.cpp StdLibraryFunctionsChecker.cpp + STLAlgorithmModeling.cpp StreamChecker.cpp Taint.cpp TaintTesterChecker.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.h b/clang/lib/StaticAnalyzer/Checkers/Iterator.h --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.h +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h @@ -159,6 +159,10 @@ 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/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp @@ -177,6 +177,20 @@ 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/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp --- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -487,12 +487,9 @@ 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 --- /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 { + 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 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(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() && + "Symbol comparison must be a `DefinedSVal`"); + StateFound = StateFound->assume(GreaterOrEqual.castAs(), 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() && + "Symbol comparison must be a `DefinedSVal`"); + StateFound = StateFound->assume(Less.castAs(), 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(); + 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 --- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -783,14 +783,121 @@ return it; } - template - InputIterator find(InputIterator first, InputIterator last, const T &val); - - template - ForwardIterator1 find_first_of(ForwardIterator1 first1, - ForwardIterator1 last1, - ForwardIterator2 first2, - ForwardIterator2 last2); + template + InputIt find(InputIt first, InputIt last, const T& value); + + template + ForwardIt find(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, + const T& value); + + template + InputIt find_if (InputIt first, InputIt last, UnaryPredicate p); + + template + ForwardIt find_if (ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, + UnaryPredicate p); + + template + InputIt find_if_not (InputIt first, InputIt last, UnaryPredicate q); + + template + ForwardIt find_if_not (ExecutionPolicy&& policy, ForwardIt first, + ForwardIt last, UnaryPredicate q); + + template + InputIt find_first_of(InputIt first, InputIt last, + ForwardIt s_first, ForwardIt s_last); + + template + ForwardIt1 find_first_of (ExecutionPolicy&& policy, + ForwardIt1 first, ForwardIt1 last, + ForwardIt2 s_first, ForwardIt2 s_last); + + template + InputIt find_first_of (InputIt first, InputIt last, + ForwardIt s_first, ForwardIt s_last, + BinaryPredicate p ); + + template + ForwardIt1 find_first_of (ExecutionPolicy&& policy, + ForwardIt1 first, ForwardIt1 last, + ForwardIt2 s_first, ForwardIt2 s_last, + BinaryPredicate p ); + + template + InputIt find_end(InputIt first, InputIt last, + ForwardIt s_first, ForwardIt s_last); + + template + ForwardIt1 find_end (ExecutionPolicy&& policy, + ForwardIt1 first, ForwardIt1 last, + ForwardIt2 s_first, ForwardIt2 s_last); + + template + InputIt find_end (InputIt first, InputIt last, + ForwardIt s_first, ForwardIt s_last, + BinaryPredicate p ); + + template + ForwardIt1 find_end (ExecutionPolicy&& policy, + ForwardIt1 first, ForwardIt1 last, + ForwardIt2 s_first, ForwardIt2 s_last, + BinaryPredicate p ); + + template + ForwardIt lower_bound (ForwardIt first, ForwardIt last, const T& value); + + template + ForwardIt lower_bound (ForwardIt first, ForwardIt last, const T& value, + Compare comp); + + template + ForwardIt upper_bound (ForwardIt first, ForwardIt last, const T& value); + + template + ForwardIt upper_bound (ForwardIt first, ForwardIt last, const T& value, + Compare comp); + + template + ForwardIt1 search (ForwardIt1 first, ForwardIt1 last, + ForwardIt2 s_first, ForwardIt2 s_last); + + template + ForwardIt1 search (ExecutionPolicy&& policy, + ForwardIt1 first, ForwardIt1 last, + ForwardIt2 s_first, ForwardIt2 s_last); + + template + ForwardIt1 search (ForwardIt1 first, ForwardIt1 last, + ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p); + + template + ForwardIt1 search (ExecutionPolicy&& policy, + ForwardIt1 first, ForwardIt1 last, + ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p); + + template + ForwardIt search (ForwardIt first, ForwardIt last, const Searcher& searcher); + + template + ForwardIt search_n (ForwardIt first, ForwardIt last, Size count, + const T& value); + + template + ForwardIt search_n (ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, + Size count, const T& value); + + template + ForwardIt search_n (ForwardIt first, ForwardIt last, Size count, + const T& value, BinaryPredicate p); + + template + ForwardIt search_n (ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, + Size count, const T& value, BinaryPredicate p); template OutputIterator copy(InputIterator first, InputIterator last, @@ -927,4 +1034,22 @@ iterator begin() const { return iterator(val); } iterator end() const { return iterator(val + 1); } }; + +namespace execution { +class sequenced_policy {}; +} + +template struct equal_to {}; + +template > +class default_searcher { +public: + default_searcher (ForwardIt pat_first, + ForwardIt pat_last, + BinaryPredicate pred = BinaryPredicate()); + template + std::pair + operator()( ForwardIt2 first, ForwardIt2 last ) const; +}; + } diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c --- 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 --- /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 +long clang_analyzer_iterator_position(const Iterator&); + +template Iter return_any_iterator(const Iter &It); + +void test_find1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +bool odd(int i) { return i % 2; } + +void test_find_if1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_if2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_if_not1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_if_not2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_first_of1(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_first_of2(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_first_of3(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_first_of4(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_end1(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_end2(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_end3(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_find_end4(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +bool compare(int, int); + +void test_lower_bound1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_lower_bound2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_upper_bound1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_upper_bound2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search1(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search2(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search3(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search4(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search5(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search_n1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search_n2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search_n3(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} + +void test_search_n4(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} + } +} diff --git a/clang/test/Analysis/stl-algorithm-modeling.cpp b/clang/test/Analysis/stl-algorithm-modeling.cpp new file mode 100644 --- /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 +long clang_analyzer_iterator_position(const Iterator&); + +template Iter return_any_iterator(const Iter &It); + +void test_find1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +bool odd(int i) { return i % 2; } + +void test_find_if1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_if2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_if_not1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_if_not2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_first_of1(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_first_of2(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_first_of3(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_first_of4(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_end1(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_end2(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_end3(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_find_end4(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +bool compare(int, int); + +void test_lower_bound1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_lower_bound2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_upper_bound1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_upper_bound2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search1(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search2(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search3(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search4(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search5(std::vector V1, std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i5) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i5) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search_n1(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search_n2(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search_n3(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +} + +void test_search_n4(std::vector 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@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i1)); // expected-warning@-1{{FALSE}} + + clang_analyzer_eval(clang_analyzer_iterator_position(i3) < + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_position(i3) >= + clang_analyzer_iterator_position(i2)); // expected-warning@-1{{FALSE}} +}