baloghadamsoftware updated this revision to Diff 274742.
baloghadamsoftware added a comment.

Rebased on `master` which now contains the handling of pointers as iterators. 
All tests passed.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77229/new/

https://reviews.llvm.org/D77229

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp

Index: clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -24,12 +24,12 @@
 namespace {
 
 class STLAlgorithmModeling : public Checker<eval::Call> {
-  bool evalFind(CheckerContext &C, const CallExpr *CE) const;
+  void evalFind(CheckerContext &C, const CallExpr *CE, SVal Begin,
+                SVal End) const;
 
-  void Find(CheckerContext &C, const CallExpr *CE, unsigned paramNum) const;
-
-  using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &,
-                                                const CallExpr *) const;
+  using FnCheck = void (STLAlgorithmModeling::*)(CheckerContext &,
+                                                 const CallExpr *, SVal Begin,
+                                                 SVal End) const;
 
   const CallDescriptionMap<FnCheck> Callbacks = {
     {{{"std", "find"}, 3}, &STLAlgorithmModeling::evalFind},
@@ -67,51 +67,53 @@
 
 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()))
+  if (Call.getNumArgs() < 2 || !isIteratorType(Call.getArgExpr(1)->getType()))
     return false;
 
+  unsigned ArgNum = 999;
+
   // 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 (isIteratorType(Call.getArgExpr(0)->getType())) {
+    ArgNum = 0;
   }
 
   // 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;
+  if (ArgNum > 0 &&
+      Call.getNumArgs() > 2 && isIteratorType(Call.getArgExpr(2)->getType())) {
+    ArgNum = 1;
   }
 
-  return false;
+  if (ArgNum == 999)
+    return false;
+
+  SVal ArgB = getIteratorArg(Call, ArgNum, C.blockCount());
+  SVal ArgE = getIteratorArg(Call, ArgNum + 1, C.blockCount());
+
+  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+  if (!CE)
+    return false;
+
+  const FnCheck *Handler = Callbacks.lookup(Call);
+  if (!Handler)
+    return false;
+
+  (this->**Handler)(C, CE, ArgB, ArgE);
+  return true;
 }
 
-void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
-                                unsigned paramNum) const {
+void STLAlgorithmModeling::evalFind(CheckerContext &C, const CallExpr *CE,
+                                    SVal Begin, SVal End) 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);
 
@@ -119,7 +121,7 @@
   // 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);
+  const auto *Pos = getIteratorPosition(State, Begin);
   if (Pos) {
     StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
                                         CE, LCtx, C.blockCount());
@@ -135,13 +137,11 @@
     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);
+  Pos = getIteratorPosition(State, End);
   if (Pos) {
     StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
                                         CE, LCtx, C.blockCount());
@@ -160,7 +160,7 @@
   C.addTransition(StateFound);
 
   if (AggressiveStdFindModeling) {
-    auto StateNotFound = State->BindExpr(CE, LCtx, Param);
+    auto StateNotFound = State->BindExpr(CE, LCtx, End);
     C.addTransition(StateNotFound);
   }
 }
Index: clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
@@ -32,16 +32,12 @@
 
   std::unique_ptr<BugType> MismatchedBugType;
 
-  void verifyMatch(CheckerContext &C, const SVal &Iter,
-                   const MemRegion *Cont) const;
-  void verifyMatch(CheckerContext &C, const SVal &Iter1,
-                   const SVal &Iter2) const;
-  void reportBug(const StringRef &Message, const SVal &Val1,
-                 const SVal &Val2, CheckerContext &C,
-                 ExplodedNode *ErrNode) const;
-  void reportBug(const StringRef &Message, const SVal &Val,
-                 const MemRegion *Reg, CheckerContext &C,
-                 ExplodedNode *ErrNode) const;
+  void verifyMatch(CheckerContext &C, SVal Iter, const MemRegion *Cont) const;
+  void verifyMatch(CheckerContext &C, SVal Iter1, SVal Iter2) const;
+  void reportBug(const StringRef &Message, SVal Val1, SVal Val2,
+                 CheckerContext &C, ExplodedNode *ErrNode) const;
+  void reportBug(const StringRef &Message, SVal Val, const MemRegion *Reg,
+                 CheckerContext &C, ExplodedNode *ErrNode) const;
 
 public:
   MismatchedIteratorChecker();
@@ -66,51 +62,55 @@
   if (!Func)
     return;
 
+  // If the call has no arguments, there is nothing to check here
+  if (Call.getNumArgs() < 1)
+    return;
+
   if (Func->isOverloadedOperator() &&
       isComparisonOperator(Func->getOverloadedOperator())) {
     // Check for comparisons of iterators of different containers
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-      if (Call.getNumArgs() < 1)
-        return;
-
       if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
           !isIteratorType(Call.getArgExpr(0)->getType()))
         return;
 
-      verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
+      verifyMatch(C, InstCall->getCXXThisVal(), Arg0);
     } else {
       if (Call.getNumArgs() < 2)
         return;
 
+      SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
       if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
           !isIteratorType(Call.getArgExpr(1)->getType()))
         return;
 
-      verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
+      verifyMatch(C, Arg0, Arg1);
     }
   } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
     const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
     if (!ContReg)
       return;
+
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
     // Check for erase, insert and emplace using iterator of another container
     if (isEraseCall(Func) || isEraseAfterCall(Func)) {
-      verifyMatch(C, Call.getArgSVal(0),
-                  InstCall->getCXXThisVal().getAsRegion());
+      verifyMatch(C, Arg0, InstCall->getCXXThisVal().getAsRegion());
       if (Call.getNumArgs() == 2) {
-        verifyMatch(C, Call.getArgSVal(1),
-                    InstCall->getCXXThisVal().getAsRegion());
+        SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+        verifyMatch(C, Arg1, InstCall->getCXXThisVal().getAsRegion());
       }
     } else if (isInsertCall(Func)) {
-      verifyMatch(C, Call.getArgSVal(0),
-                  InstCall->getCXXThisVal().getAsRegion());
+      verifyMatch(C, Arg0, InstCall->getCXXThisVal().getAsRegion());
       if (Call.getNumArgs() == 3 &&
           isIteratorType(Call.getArgExpr(1)->getType()) &&
           isIteratorType(Call.getArgExpr(2)->getType())) {
-        verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
+        SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+        SVal Arg2 = getIteratorArg(Call, 2, C.blockCount());
+        verifyMatch(C, Arg1, Arg2);
       }
     } else if (isEmplaceCall(Func)) {
-      verifyMatch(C, Call.getArgSVal(0),
-                  InstCall->getCXXThisVal().getAsRegion());
+      verifyMatch(C, Arg0, InstCall->getCXXThisVal().getAsRegion());
     }
   } else if (isa<CXXConstructorCall>(&Call)) {
     // Check match of first-last iterator pair in a constructor of a container
@@ -129,7 +129,9 @@
         !isIteratorType(Call.getArgExpr(1)->getType()))
       return;
 
-    verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+    SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+    verifyMatch(C, Arg0, Arg1);
   } else {
     // The main purpose of iterators is to abstract away from different
     // containers and provide a (maybe limited) uniform access to them.
@@ -167,7 +169,7 @@
       if (!isIteratorType(TAType))
         continue;
 
-      SVal LHS = UndefinedVal();
+      Optional<SVal> LHS = None;
 
       // For every template parameter which is an iterator type in the
       // instantiation look for all functions' parameters' type by it and
@@ -179,10 +181,13 @@
         if (!ParamType ||
             ParamType->getReplacedParameter()->getDecl() != TPDecl)
           continue;
-        if (LHS.isUndef()) {
-          LHS = Call.getArgSVal(J);
+
+        SVal ArgJ = getIteratorArg(Call, J, C.blockCount());
+
+        if (!LHS.hasValue()) {
+          LHS = ArgJ;
         } else {
-          verifyMatch(C, LHS, Call.getArgSVal(J));
+          verifyMatch(C, *LHS, ArgJ);
         }
       }
     }
@@ -200,7 +205,7 @@
   verifyMatch(C, LVal, RVal);
 }
 
-void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
+void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, SVal Iter,
                                             const MemRegion *Cont) const {
   // Verify match between a container and the container of an iterator
   Cont = Cont->getMostDerivedObjectRegion();
@@ -231,14 +236,13 @@
     if (!N) {
       return;
     }
-    reportBug("Container accessed using foreign iterator argument.",
-                        Iter, Cont, C, N);
+    reportBug("Container accessed using foreign iterator argument.", Iter, Cont,
+              C, N);
   }
 }
 
-void MismatchedIteratorChecker::verifyMatch(CheckerContext &C,
-                                            const SVal &Iter1,
-                                            const SVal &Iter2) const {
+void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, SVal Iter1,
+                                            SVal Iter2) const {
   // Verify match between the containers of two iterators
   auto State = C.getState();
   const auto *Pos1 = getIteratorPosition(State, Iter1);
@@ -275,10 +279,8 @@
   }
 }
 
-void MismatchedIteratorChecker::reportBug(const StringRef &Message,
-                                          const SVal &Val1,
-                                          const SVal &Val2,
-                                          CheckerContext &C,
+void MismatchedIteratorChecker::reportBug(const StringRef &Message, SVal Val1,
+                                          SVal Val2, CheckerContext &C,
                                           ExplodedNode *ErrNode) const {
   auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
                                                     ErrNode);
@@ -287,8 +289,8 @@
   C.emitReport(std::move(R));
 }
 
-void MismatchedIteratorChecker::reportBug(const StringRef &Message,
-                                          const SVal &Val, const MemRegion *Reg,
+void MismatchedIteratorChecker::reportBug(const StringRef &Message, SVal Val,
+                                          const MemRegion *Reg,
                                           CheckerContext &C,
                                           ExplodedNode *ErrNode) const {
   auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
Index: clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
@@ -83,24 +83,25 @@
   if (!Func)
     return;
 
+  SVal Arg0;
+  if (Call.getNumArgs() >= 1)
+    Arg0 = getIteratorArg(Call, 0, C.blockCount());
+
   if (Func->isOverloadedOperator()) {
+    llvm::errs()<<"Overloaded operator\n";
     if (isIncrementOperator(Func->getOverloadedOperator())) {
       // Check for out-of-range incrementions
       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
         verifyIncrement(C, InstCall->getCXXThisVal());
       } else {
-        if (Call.getNumArgs() >= 1) {
-          verifyIncrement(C, Call.getArgSVal(0));
-        }
+        verifyIncrement(C, Arg0);
       }
     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
       // Check for out-of-range decrementions
       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
         verifyDecrement(C, InstCall->getCXXThisVal());
       } else {
-        if (Call.getNumArgs() >= 1) {
-          verifyDecrement(C, Call.getArgSVal(0));
-        }
+        verifyDecrement(C, Arg0);
       }
     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
@@ -115,7 +116,7 @@
         if (Call.getNumArgs() >= 2 &&
             Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
-                                 Call.getArgSVal(0), Call.getArgSVal(1));
+                                 Arg0, Call.getArgSVal(1));
         }
       }
     } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
@@ -123,18 +124,20 @@
       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
         verifyDereference(C, InstCall->getCXXThisVal());
       } else {
-        verifyDereference(C, Call.getArgSVal(0));
+        verifyDereference(C, Arg0);
       }
     }
   } else {
     const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
     if (Verifier) {
+      SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+
       if (Call.getNumArgs() > 1) {
-        (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
+        (this->**Verifier)(C, Arg0, Call.getArgSVal(1));
       } else {
         auto &BVF = C.getSValBuilder().getBasicValueFactory();
         (this->**Verifier)(
-            C, Call.getArgSVal(0),
+            C, Arg0,
             nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
       }
     }
Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -84,9 +84,8 @@
 
 class IteratorModeling
     : public Checker<check::PostCall, check::PostStmt<UnaryOperator>,
-                     check::PostStmt<BinaryOperator>,
-                     check::PostStmt<MaterializeTemporaryExpr>,
-                     check::Bind, check::LiveSymbols, check::DeadSymbols> {
+                     check::PostStmt<BinaryOperator>, check::Bind,
+                     check::LiveSymbols, check::DeadSymbols> {
 
   using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *,
                                                SVal, SVal, SVal) const;
@@ -98,27 +97,27 @@
                                  const AdvanceFn *Handler) const;
 
   void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
-                        const SVal &LVal, const SVal &RVal,
-                        OverloadedOperatorKind Op) const;
+                        SVal LVal, SVal RVal, OverloadedOperatorKind Op) const;
   void processComparison(CheckerContext &C, ProgramStateRef State,
-                         SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal,
+                         SymbolRef Sym1, SymbolRef Sym2, SVal RetVal,
                          OverloadedOperatorKind Op) const;
-  void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
-                       bool Postfix) const;
-  void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
-                       bool Postfix) const;
+  void handleIncrement(CheckerContext &C, SVal RetVal,
+                       SVal Iter, bool Postfix) const;
+  void handleDecrement(CheckerContext &C, SVal RetVal,
+                       SVal Iter, bool Postfix) const;
   void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
-                              OverloadedOperatorKind Op, const SVal &RetVal,
-                              const SVal &LHS, const SVal &RHS) const;
+                              OverloadedOperatorKind Op,
+                              SVal RetVal, SVal LHS,
+                              SVal RHS) const;
   void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator,
                            OverloadedOperatorKind OK, SVal Offset) const;
-  void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
-                     SVal Amount) const;
-  void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
-                  SVal Amount) const;
-  void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
-                  SVal Amount) const;
-  void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
+  void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal,
+                     SVal Iter, SVal Amount) const;
+  void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal,
+                  SVal Iter, SVal Amount) const;
+  void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal,
+                  SVal Iter, SVal Amount) const;
+  void assignToContainer(CheckerContext &C, const Expr *CE, SVal RetVal,
                          const MemRegion *Cont) const;
   bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const;
   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
@@ -152,19 +151,15 @@
   void checkPostStmt(const BinaryOperator *BO, CheckerContext &C) const;
   void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
   void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
-  void checkPostStmt(const MaterializeTemporaryExpr *MTE,
-                     CheckerContext &C) const;
   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
 };
 
 bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
 bool isSimpleComparisonOperator(BinaryOperatorKind OK);
-ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, SVal Val);
 ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
                               SymbolRef Sym2, bool Equal);
-bool isBoundThroughLazyCompoundVal(const Environment &Env,
-                                   const MemRegion *Reg);
 const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call);
 
 } // namespace
@@ -198,15 +193,17 @@
   auto State = C.getState();
 
   // Already bound to container?
-  if (getIteratorPosition(State, Call.getReturnValue()))
+  SVal RetVal = getReturnIterator(Call);
+  if (getIteratorPosition(State, RetVal))
     return;
 
   // Copy-like and move constructors
   if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
-    if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
-      State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
+    SVal Arg = getIteratorArg(Call, 0, C.blockCount());
+    if (const auto *Pos = getIteratorPosition(State, Arg)) {
+      State = setIteratorPosition(State, RetVal, *Pos);
       if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
-        State = removeIteratorPosition(State, Call.getArgSVal(0));
+        State = removeIteratorPosition(State, Arg);
       }
       C.addTransition(State);
       return;
@@ -224,8 +221,7 @@
             C.getASTContext()).getTypePtr() ==
         Call.getResultType().getDesugaredType(C.getASTContext()).getTypePtr()) {
       if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
-        assignToContainer(C, OrigExpr, Call.getReturnValue(),
-                          Pos->getContainer());
+        assignToContainer(C, OrigExpr, RetVal, Pos->getContainer());
         return;
       }
     }
@@ -235,6 +231,9 @@
 void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S,
                                  CheckerContext &C) const {
   auto State = C.getState();
+  if (Val.getAs<nonloc::LazyCompoundVal>())
+    return;
+
   const auto *Pos = getIteratorPosition(State, Val);
   if (Pos) {
     State = setIteratorPosition(State, Loc, *Pos);
@@ -277,17 +276,6 @@
   }
 }
 
-void IteratorModeling::checkPostStmt(const MaterializeTemporaryExpr *MTE,
-                                     CheckerContext &C) const {
-  /* Transfer iterator state to temporary objects */
-  auto State = C.getState();
-  const auto *Pos = getIteratorPosition(State, C.getSVal(MTE->getSubExpr()));
-  if (!Pos)
-    return;
-  State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
-  C.addTransition(State);
-}
-
 void IteratorModeling::checkLiveSymbols(ProgramStateRef State,
                                         SymbolReaper &SR) const {
   // Keep symbolic expressions of iterator positions alive
@@ -295,8 +283,9 @@
   for (const auto &Reg : RegionMap) {
     const auto Offset = Reg.second.getOffset();
     for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
-      if (isa<SymbolData>(*i))
+      if (isa<SymbolData>(*i)) {
         SR.markLive(*i);
+      }
   }
 
   auto SymbolMap = State->get<IteratorSymbolMap>();
@@ -317,12 +306,7 @@
   auto RegionMap = State->get<IteratorRegionMap>();
   for (const auto &Reg : RegionMap) {
     if (!SR.isLiveRegion(Reg.first)) {
-      // The region behind the `LazyCompoundVal` is often cleaned up before
-      // the `LazyCompoundVal` itself. If there are iterator positions keyed
-      // by these regions their cleanup must be deferred.
-      if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
-        State = State->remove<IteratorRegionMap>(Reg.first);
-      }
+      State = State->remove<IteratorRegionMap>(Reg.first);
     }
   }
 
@@ -340,61 +324,63 @@
 IteratorModeling::handleOverloadedOperator(CheckerContext &C,
                                            const CallEvent &Call,
                                            OverloadedOperatorKind Op) const {
-    if (isSimpleComparisonOperator(Op)) {
-      const auto *OrigExpr = Call.getOriginExpr();
-      if (!OrigExpr)
-        return;
+  const auto *OrigExpr = Call.getOriginExpr();
+  if (!OrigExpr)
+    return;
 
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        handleComparison(C, OrigExpr, Call.getReturnValue(),
-                         InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
-        return;
-      }
+  if (isSimpleComparisonOperator(Op)) {
+    const auto *OrigExpr = Call.getOriginExpr();
+    if (!OrigExpr)
+      return;
 
-      handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
-                         Call.getArgSVal(1), Op);
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleComparison(C, OrigExpr, Call.getReturnValue(),
+                       InstCall->getCXXThisVal(), Arg0, Op);
       return;
-    } else if (isRandomIncrOrDecrOperator(Op)) {
-      const auto *OrigExpr = Call.getOriginExpr();
-      if (!OrigExpr)
-        return;
+    }
 
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        if (Call.getNumArgs() >= 1 &&
-              Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
-          handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
-                                 InstCall->getCXXThisVal(), Call.getArgSVal(0));
-          return;
-        }
-      } else {
-        if (Call.getNumArgs() >= 2 &&
-              Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
-          handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
-                                 Call.getArgSVal(0), Call.getArgSVal(1));
-          return;
-        }
+    SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+    handleComparison(C, OrigExpr, Call.getReturnValue(), Arg0, Arg1, Op);
+    return;
+  } else if (isRandomIncrOrDecrOperator(Op)) {
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      if (Call.getNumArgs() >= 1 &&
+          Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
+        handleRandomIncrOrDecr(C, OrigExpr, Op, getReturnIterator(Call),
+                               InstCall->getCXXThisVal(), Call.getArgSVal(0));
+        return;
       }
-    } else if (isIncrementOperator(Op)) {
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
-                        Call.getNumArgs());
+    } else {
+      if (Call.getNumArgs() >= 2 &&
+          Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
+        SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+        handleRandomIncrOrDecr(C, OrigExpr, Op, getReturnIterator(Call), Arg0,
+                               Call.getArgSVal(1));
         return;
       }
-
-      handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
+    }
+  } else if (isIncrementOperator(Op)) {
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleIncrement(C, getReturnIterator(Call), InstCall->getCXXThisVal(),
                       Call.getNumArgs());
       return;
-    } else if (isDecrementOperator(Op)) {
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
-                        Call.getNumArgs());
-        return;
-      }
+    }
 
-      handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
-                        Call.getNumArgs());
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+    handleIncrement(C, getReturnIterator(Call), Arg0, Call.getNumArgs());
+    return;
+  } else if (isDecrementOperator(Op)) {
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleDecrement(C, getReturnIterator(Call), InstCall->getCXXThisVal(),
+                      Call.getNumArgs());
       return;
     }
+
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+    handleDecrement(C, getReturnIterator(Call), Arg0, Call.getNumArgs());
+    return;
+  }
 }
 
 void
@@ -402,9 +388,10 @@
                                             const CallEvent &Call,
                                             const Expr *OrigExpr,
                                             const AdvanceFn *Handler) const {
-  if (!C.wasInlined) {
-    (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
-                      Call.getArgSVal(0), Call.getArgSVal(1));
+  SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+   if (!C.wasInlined) {
+     (this->**Handler)(C, OrigExpr, getReturnIterator(Call), Arg0,
+                       Call.getArgSVal(1));
     return;
   }
 
@@ -413,23 +400,22 @@
   const auto *IdInfo = cast<FunctionDecl>(Call.getDecl())->getIdentifier();
   if (IdInfo) {
     if (IdInfo->getName() == "advance") {
-      if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) {
-        (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
-                          Call.getArgSVal(0), Call.getArgSVal(1));
+      if (noChangeInAdvance(C, Arg0, OrigExpr)) {
+        (this->**Handler)(C, OrigExpr, getReturnIterator(Call), Arg0,
+                          Call.getArgSVal(1));
       }
     }
   }
 }
 
 void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
-                                       SVal RetVal, const SVal &LVal,
-                                       const SVal &RVal,
-                                       OverloadedOperatorKind Op) const {
+                                        SVal RetVal, SVal LVal, SVal RVal,
+                                        OverloadedOperatorKind Op) const {
   // Record the operands and the operator of the comparison for the next
   // evalAssume, if the result is a symbolic expression. If it is a concrete
   // value (only one branch is possible), then transfer the state between
   // the operands according to the operator and the result
-   auto State = C.getState();
+  auto State = C.getState();
   const auto *LPos = getIteratorPosition(State, LVal);
   const auto *RPos = getIteratorPosition(State, RVal);
   const MemRegion *Cont = nullptr;
@@ -476,7 +462,7 @@
 
 void IteratorModeling::processComparison(CheckerContext &C,
                                          ProgramStateRef State, SymbolRef Sym1,
-                                         SymbolRef Sym2, const SVal &RetVal,
+                                         SymbolRef Sym2, SVal RetVal,
                                          OverloadedOperatorKind Op) const {
   if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
     if ((State = relateSymbols(State, Sym1, Sym2,
@@ -504,8 +490,8 @@
   }
 }
 
-void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal,
-                                       const SVal &Iter, bool Postfix) const {
+void IteratorModeling::handleIncrement(CheckerContext &C, SVal RetVal,
+                                       SVal Iter, bool Postfix) const {
   // Increment the symbolic expressions which represents the position of the
   // iterator
   auto State = C.getState();
@@ -530,8 +516,8 @@
   C.addTransition(State);
 }
 
-void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal,
-                                       const SVal &Iter, bool Postfix) const {
+void IteratorModeling::handleDecrement(CheckerContext &C, SVal RetVal,
+                                       SVal Iter, bool Postfix) const {
   // Decrement the symbolic expressions which represents the position of the
   // iterator
   auto State = C.getState();
@@ -559,32 +545,32 @@
 void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C,
                                               const Expr *CE,
                                               OverloadedOperatorKind Op,
-                                              const SVal &RetVal,
-                                              const SVal &LHS,
-                                              const SVal &RHS) const {
+                                              SVal RetVal, SVal Iter,
+                                              SVal Amount) const {
   // Increment or decrement the symbolic expressions which represents the
   // position of the iterator
   auto State = C.getState();
 
-  const auto *Pos = getIteratorPosition(State, LHS);
+  const auto *Pos = getIteratorPosition(State, Iter);
   if (!Pos)
     return;
 
-  const auto *value = &RHS;
-  SVal val;
-  if (auto loc = RHS.getAs<Loc>()) {
-    val = State->getRawSVal(*loc);
-    value = &val;
+  const auto *AmountVal = &Amount;
+  SVal AmountV;
+  if (auto L = Amount.getAs<Loc>()) {
+    AmountV = State->getRawSVal(*L);
+    AmountVal = &AmountV;
   }
 
-  auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal;
+  SVal TgtVal =
+    (Op == OO_PlusEqual || Op == OO_MinusEqual) ? Iter : RetVal;
 
   // `AdvancedState` is a state where the position of `LHS` is advanced. We
   // only need this state to retrieve the new position, but we do not want
   // to change the position of `LHS` (in every case).
-  auto AdvancedState = advancePosition(State, LHS, Op, *value);
+  auto AdvancedState = advancePosition(State, Iter, Op, *AmountVal);
   if (AdvancedState) {
-    const auto *NewPos = getIteratorPosition(AdvancedState, LHS);
+    const auto *NewPos = getIteratorPosition(AdvancedState, Iter);
     assert(NewPos &&
            "Iterator should have position after successful advancement");
 
@@ -645,17 +631,19 @@
 }
 
 void IteratorModeling::handlePrev(CheckerContext &C, const Expr *CE,
-                                  SVal RetVal, SVal Iter, SVal Amount) const {
+                                  SVal RetVal, SVal Iter,
+                                  SVal Amount) const {
   handleRandomIncrOrDecr(C, CE, OO_Minus, RetVal, Iter, Amount);
 }
 
 void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE,
-                                  SVal RetVal, SVal Iter, SVal Amount) const {
+                                  SVal RetVal, SVal Iter,
+                                  SVal Amount) const {
   handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount);
 }
 
 void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
-                                         const SVal &RetVal,
+                                         SVal RetVal,
                                          const MemRegion *Cont) const {
   Cont = Cont->getMostDerivedObjectRegion();
 
@@ -738,16 +726,14 @@
   return OK == BO_EQ || OK == BO_NE;
 }
 
-ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, SVal Val) {
   if (auto Reg = Val.getAsRegion()) {
     Reg = Reg->getMostDerivedObjectRegion();
     return State->remove<IteratorRegionMap>(Reg);
   } else if (const auto Sym = Val.getAsSymbol()) {
     return State->remove<IteratorSymbolMap>(Sym);
-  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
-    return State->remove<IteratorRegionMap>(LCVal->getRegion());
   }
-  return nullptr;
+  return State;
 }
 
 ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
@@ -782,18 +768,6 @@
   return NewState;
 }
 
-bool isBoundThroughLazyCompoundVal(const Environment &Env,
-                                   const MemRegion *Reg) {
-  for (const auto &Binding : Env) {
-    if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
-      if (LCVal->getRegion() == Reg)
-        return true;
-    }
-  }
-
-  return false;
-}
-
 const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call) {
   while (Node) {
     ProgramPoint PP = Node->getLocation();
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.h
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/Iterator.h
+++ clang/lib/StaticAnalyzer/Checkers/Iterator.h
@@ -184,6 +184,17 @@
 bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
              BinaryOperator::Opcode Opc);
 
+// Returns the value of the iterator argument if it non-class value (a pointer
+// or a reference). Otherwise it returns the iterator parameter location (see
+// CallEvent::getParameterLocation()).
+SVal getIteratorArg(const CallEvent &Call, unsigned Index, unsigned BlockCount);
+
+// If the call returns an class instance iterator by value then this function
+// retrieves and returns it from the construction context of the call.
+// Otherwise (for non-class types) it simply returns the return value of the
+// call.
+SVal getReturnIterator(const CallEvent &Call);
+
 } // namespace iterator
 } // namespace ento
 } // namespace clang
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
+++ clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
@@ -10,6 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+
 #include "Iterator.h"
 
 namespace clang {
@@ -188,8 +190,6 @@
     return State->get<IteratorRegionMap>(Reg);
   } else if (const auto Sym = Val.getAsSymbol()) {
     return State->get<IteratorSymbolMap>(Sym);
-  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
-    return State->get<IteratorRegionMap>(LCVal->getRegion());
   }
   return nullptr;
 }
@@ -201,10 +201,8 @@
     return State->set<IteratorRegionMap>(Reg, Pos);
   } else if (const auto Sym = Val.getAsSymbol()) {
     return State->set<IteratorSymbolMap>(Sym, Pos);
-  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
-    return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
   }
-  return nullptr;
+  return State;
 }
 
 ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
@@ -314,6 +312,29 @@
   return !State->assume(comparison.castAs<DefinedSVal>(), false);
 }
 
+SVal getIteratorArg(const CallEvent& Call, unsigned Index,
+                    unsigned BlockCount) {
+  SVal Arg = Call.getArgSVal(Index);
+  const Expr *ArgExpr = Call.getArgExpr(Index);
+
+  if (ArgExpr->getValueKind() != VK_RValue)
+    return Arg;
+
+  if (!ArgExpr->getType().getDesugaredType(
+          Call.getState()->getStateManager().getContext())->isRecordType())
+    return Arg;
+
+  return loc::MemRegionVal(Call.getParameterLocation(Index, BlockCount));
+}
+
+SVal getReturnIterator(const CallEvent &Call) {
+  Optional<SVal> RetValUnderConstr = Call.getReturnValueUnderConstruction();
+  if (RetValUnderConstr.hasValue())
+    return *RetValUnderConstr;
+
+  return Call.getReturnValue();
+}
+
 } // namespace iterator
 } // namespace ento
 } // namespace clang
Index: clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
@@ -33,9 +33,9 @@
 
   std::unique_ptr<BugType> InvalidatedBugType;
 
-  void verifyAccess(CheckerContext &C, const SVal &Val) const;
-  void reportBug(const StringRef &Message, const SVal &Val,
-                 CheckerContext &C, ExplodedNode *ErrNode) const;
+  void verifyAccess(CheckerContext &C, SVal Val) const;
+  void reportBug(const StringRef &Message, SVal Val, CheckerContext &C,
+                 ExplodedNode *ErrNode) const;
 public:
   InvalidatedIteratorChecker();
 
@@ -67,7 +67,8 @@
     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
       verifyAccess(C, InstCall->getCXXThisVal());
     } else {
-      verifyAccess(C, Call.getArgSVal(0));
+      SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+      verifyAccess(C, Arg0);
     }
   }
 }
@@ -114,7 +115,8 @@
   verifyAccess(C, BaseVal);
 }
 
-void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
+void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C,
+                                              SVal Val) const {
   auto State = C.getState();
   const auto *Pos = getIteratorPosition(State, Val);
   if (Pos && !Pos->isValid()) {
@@ -127,7 +129,7 @@
 }
 
 void InvalidatedIteratorChecker::reportBug(const StringRef &Message,
-                                           const SVal &Val, CheckerContext &C,
+                                           SVal Val, CheckerContext &C,
                                            ExplodedNode *ErrNode) const {
   auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
                                                     Message, ErrNode);
Index: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -179,39 +179,46 @@
     }
   } else {
     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-      const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
-      if (Handler0) {
-        (this->**Handler0)(C, InstCall->getCXXThisVal(),
-                           InstCall->getCXXThisExpr());
+      const auto *OrigExpr = Call.getOriginExpr();
+      if (!OrigExpr)
+        return;
+
+      if (isBeginCall(Func)) {
+        handleBegin(C, OrigExpr, getReturnIterator(Call),
+                    InstCall->getCXXThisVal());
         return;
       }
 
-      const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call);
-      if (Handler1) {
-        (this->**Handler1)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
+      if (isEndCall(Func)) {
+        handleEnd(C, OrigExpr, getReturnIterator(Call),
+                  InstCall->getCXXThisVal());
         return;
       }
 
-      const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call);
-      if (Handler2) {
-        (this->**Handler2)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0),
-                           Call.getArgSVal(1));
+      const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
+      if (Handler0) {
+        (this->**Handler0)(C, InstCall->getCXXThisVal(),
+                           InstCall->getCXXThisExpr());
         return;
       }
 
-      const auto *OrigExpr = Call.getOriginExpr();
-      if (!OrigExpr)
+      if (Call.getNumArgs() < 1)
         return;
 
-      if (isBeginCall(Func)) {
-        handleBegin(C, OrigExpr, Call.getReturnValue(),
-                    InstCall->getCXXThisVal());
+      SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+      const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call);
+      if (Handler1) {
+        (this->**Handler1)(C, InstCall->getCXXThisVal(), Arg0);
         return;
       }
 
-      if (isEndCall(Func)) {
-        handleEnd(C, OrigExpr, Call.getReturnValue(),
-                  InstCall->getCXXThisVal());
+      if (Call.getNumArgs() < 2)
+        return;
+
+      SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+      const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call);
+      if (Handler2) {
+        (this->**Handler2)(C, InstCall->getCXXThisVal(), Arg0, Arg1);
         return;
       }
     }
@@ -257,7 +264,7 @@
 }
 
 void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
-                                   SVal RetVal, SVal Cont) const {
+                                    SVal RetVal, SVal Cont) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -273,13 +280,14 @@
                                  C.getLocationContext(), C.blockCount());
     BeginSym = getContainerBegin(State, ContReg);
   }
+
   State = setIteratorPosition(State, RetVal,
                               IteratorPosition::getPosition(ContReg, BeginSym));
   C.addTransition(State);
 }
 
 void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
-                                 SVal RetVal, SVal Cont) const {
+                                  SVal RetVal, SVal Cont) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -295,6 +303,7 @@
                                C.getLocationContext(), C.blockCount());
     EndSym = getContainerEnd(State, ContReg);
   }
+
   State = setIteratorPosition(State, RetVal,
                               IteratorPosition::getPosition(ContReg, EndSym));
   C.addTransition(State);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D77229: [Analyzer]... Balogh , Ádám via Phabricator via cfe-commits
    • [PATCH] D77229: [Anal... Balogh , Ádám via Phabricator via cfe-commits

Reply via email to