[clang] dd1d548 - [analyzer][Liveness][NFC] Get rid of statement liveness, because such a thing doesn't exist

Kristóf Umann via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 15 08:45:29 PDT 2020


Author: Kristóf Umann
Date: 2020-09-15T17:43:02+02:00
New Revision: dd1d5488e47d0a89217dfd22a726c3d3ad2b4984

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

LOG: [analyzer][Liveness][NFC] Get rid of statement liveness, because such a thing doesn't exist

The summary and very short discussion in D82122 summarizes whats happening here.

In short, liveness talks about variables, or expressions, anything that
has a value. Well, statements just simply don't have a one.

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

Added: 
    

Modified: 
    clang/docs/analyzer/developer-docs/DebugChecks.rst
    clang/include/clang/Analysis/Analyses/LiveVariables.h
    clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
    clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
    clang/lib/Analysis/LiveVariables.cpp
    clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
    clang/lib/StaticAnalyzer/Core/Environment.cpp
    clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
    clang/test/Analysis/live-stmts.cpp
    clang/test/Analysis/live-stmts.mm

Removed: 
    


################################################################################
diff  --git a/clang/docs/analyzer/developer-docs/DebugChecks.rst b/clang/docs/analyzer/developer-docs/DebugChecks.rst
index 48b584a46307..45985a1dfd79 100644
--- a/clang/docs/analyzer/developer-docs/DebugChecks.rst
+++ b/clang/docs/analyzer/developer-docs/DebugChecks.rst
@@ -30,7 +30,7 @@ using a 'dot' format viewer (such as Graphviz on macOS) instead.
 - debug.DumpLiveVars: Show the results of live variable analysis for each
   top-level function being analyzed.
 
-- debug.DumpLiveStmts: Show the results of live statement analysis for each
+- debug.DumpLiveExprs: Show the results of live expression analysis for each
   top-level function being analyzed.
 
 - debug.ViewExplodedGraph: Show the Exploded Graphs generated for the

diff  --git a/clang/include/clang/Analysis/Analyses/LiveVariables.h b/clang/include/clang/Analysis/Analyses/LiveVariables.h
index 2e7dd5d81678..8a3dd0c35e64 100644
--- a/clang/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/clang/include/clang/Analysis/Analyses/LiveVariables.h
@@ -30,22 +30,22 @@ class LiveVariables : public ManagedAnalysis {
   class LivenessValues {
   public:
 
-    llvm::ImmutableSet<const Stmt *> liveStmts;
+    llvm::ImmutableSet<const Expr *> liveExprs;
     llvm::ImmutableSet<const VarDecl *> liveDecls;
     llvm::ImmutableSet<const BindingDecl *> liveBindings;
 
     bool equals(const LivenessValues &V) const;
 
     LivenessValues()
-      : liveStmts(nullptr), liveDecls(nullptr), liveBindings(nullptr) {}
+      : liveExprs(nullptr), liveDecls(nullptr), liveBindings(nullptr) {}
 
-    LivenessValues(llvm::ImmutableSet<const Stmt *> LiveStmts,
+    LivenessValues(llvm::ImmutableSet<const Expr *> liveExprs,
                    llvm::ImmutableSet<const VarDecl *> LiveDecls,
                    llvm::ImmutableSet<const BindingDecl *> LiveBindings)
-        : liveStmts(LiveStmts), liveDecls(LiveDecls),
+        : liveExprs(liveExprs), liveDecls(LiveDecls),
           liveBindings(LiveBindings) {}
 
-    bool isLive(const Stmt *S) const;
+    bool isLive(const Expr *E) const;
     bool isLive(const VarDecl *D) const;
 
     friend class LiveVariables;
@@ -83,17 +83,17 @@ class LiveVariables : public ManagedAnalysis {
   ///  only returns liveness information for block-level expressions.
   bool isLive(const Stmt *S, const VarDecl *D);
 
-  /// Returns true the block-level expression "value" is live
+  /// Returns true the block-level expression value is live
   ///  before the given block-level expression (see runOnAllBlocks).
-  bool isLive(const Stmt *Loc, const Stmt *StmtVal);
+  bool isLive(const Stmt *Loc, const Expr *Val);
 
   /// Print to stderr the variable liveness information associated with
   /// each basic block.
   void dumpBlockLiveness(const SourceManager &M);
 
-  /// Print to stderr the statement liveness information associated with
+  /// Print to stderr the expression liveness information associated with
   /// each basic block.
-  void dumpStmtLiveness(const SourceManager &M);
+  void dumpExprLiveness(const SourceManager &M);
 
   void runOnAllBlocks(Observer &obs);
 

diff  --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index cbc048ba74c4..3540fe5fe55c 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1478,8 +1478,8 @@ def LiveVariablesDumper : Checker<"DumpLiveVars">,
   HelpText<"Print results of live variable analysis">,
   Documentation<NotDocumented>;
 
-def LiveStatementsDumper : Checker<"DumpLiveStmts">,
-  HelpText<"Print results of live statement analysis">,
+def LiveExpressionsDumper : Checker<"DumpLiveExprs">,
+  HelpText<"Print results of live expression analysis">,
   Documentation<NotDocumented>;
 
 def CFGViewer : Checker<"ViewCFG">,

diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 75dfbde5c151..c71cb88f5574 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -539,7 +539,7 @@ class SymbolReaper {
 
   bool isLive(SymbolRef sym);
   bool isLiveRegion(const MemRegion *region);
-  bool isLive(const Stmt *ExprVal, const LocationContext *LCtx) const;
+  bool isLive(const Expr *ExprVal, const LocationContext *LCtx) const;
   bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const;
 
   /// Unconditionally marks a symbol as live.

diff  --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp
index d24c40b457b4..8cdc4cc5bd61 100644
--- a/clang/lib/Analysis/LiveVariables.cpp
+++ b/clang/lib/Analysis/LiveVariables.cpp
@@ -27,7 +27,7 @@ namespace {
 class LiveVariablesImpl {
 public:
   AnalysisDeclContext &analysisContext;
-  llvm::ImmutableSet<const Stmt *>::Factory SSetFact;
+  llvm::ImmutableSet<const Expr *>::Factory ESetFact;
   llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
   llvm::ImmutableSet<const BindingDecl *>::Factory BSetFact;
   llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
@@ -45,16 +45,15 @@ class LiveVariablesImpl {
              LiveVariables::Observer *obs = nullptr);
 
   void dumpBlockLiveness(const SourceManager& M);
-  void dumpStmtLiveness(const SourceManager& M);
+  void dumpExprLiveness(const SourceManager& M);
 
   LiveVariablesImpl(AnalysisDeclContext &ac, bool KillAtAssign)
-    : analysisContext(ac),
-      SSetFact(false), // Do not canonicalize ImmutableSets by default.
-      DSetFact(false), // This is a *major* performance win.
-      BSetFact(false),
-      killAtAssign(KillAtAssign) {}
+      : analysisContext(ac),
+        ESetFact(false), // Do not canonicalize ImmutableSets by default.
+        DSetFact(false), // This is a *major* performance win.
+        BSetFact(false), killAtAssign(KillAtAssign) {}
 };
-}
+} // namespace
 
 static LiveVariablesImpl &getImpl(void *x) {
   return *((LiveVariablesImpl *) x);
@@ -64,8 +63,8 @@ static LiveVariablesImpl &getImpl(void *x) {
 // Operations and queries on LivenessValues.
 //===----------------------------------------------------------------------===//
 
-bool LiveVariables::LivenessValues::isLive(const Stmt *S) const {
-  return liveStmts.contains(S);
+bool LiveVariables::LivenessValues::isLive(const Expr *E) const {
+  return liveExprs.contains(E);
 }
 
 bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const {
@@ -97,10 +96,10 @@ LiveVariables::LivenessValues
 LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA,
                          LiveVariables::LivenessValues valsB) {
 
-  llvm::ImmutableSetRef<const Stmt *>
-    SSetRefA(valsA.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()),
-    SSetRefB(valsB.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory());
-
+  llvm::ImmutableSetRef<const Expr *> SSetRefA(
+      valsA.liveExprs.getRootWithoutRetain(), ESetFact.getTreeFactory()),
+      SSetRefB(valsB.liveExprs.getRootWithoutRetain(),
+               ESetFact.getTreeFactory());
 
   llvm::ImmutableSetRef<const VarDecl *>
     DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()),
@@ -122,7 +121,7 @@ LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA,
 }
 
 bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const {
-  return liveStmts == V.liveStmts && liveDecls == V.liveDecls;
+  return liveExprs == V.liveExprs && liveDecls == V.liveDecls;
 }
 
 //===----------------------------------------------------------------------===//
@@ -141,8 +140,8 @@ bool LiveVariables::isLive(const Stmt *S, const VarDecl *D) {
   return isAlwaysAlive(D) || getImpl(impl).stmtsToLiveness[S].isLive(D);
 }
 
-bool LiveVariables::isLive(const Stmt *Loc, const Stmt *S) {
-  return getImpl(impl).stmtsToLiveness[Loc].isLive(S);
+bool LiveVariables::isLive(const Stmt *Loc, const Expr *Val) {
+  return getImpl(impl).stmtsToLiveness[Loc].isLive(Val);
 }
 
 //===----------------------------------------------------------------------===//
@@ -186,27 +185,27 @@ static const VariableArrayType *FindVA(QualType Ty) {
   return nullptr;
 }
 
-static const Stmt *LookThroughStmt(const Stmt *S) {
-  while (S) {
-    if (const Expr *Ex = dyn_cast<Expr>(S))
-      S = Ex->IgnoreParens();
-    if (const FullExpr *FE = dyn_cast<FullExpr>(S)) {
-      S = FE->getSubExpr();
+static const Expr *LookThroughExpr(const Expr *E) {
+  while (E) {
+    if (const Expr *Ex = dyn_cast<Expr>(E))
+      E = Ex->IgnoreParens();
+    if (const FullExpr *FE = dyn_cast<FullExpr>(E)) {
+      E = FE->getSubExpr();
       continue;
     }
-    if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) {
-      S = OVE->getSourceExpr();
+    if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) {
+      E = OVE->getSourceExpr();
       continue;
     }
     break;
   }
-  return S;
+  return E;
 }
 
-static void AddLiveStmt(llvm::ImmutableSet<const Stmt *> &Set,
-                        llvm::ImmutableSet<const Stmt *>::Factory &F,
-                        const Stmt *S) {
-  Set = F.add(Set, LookThroughStmt(S));
+static void AddLiveExpr(llvm::ImmutableSet<const Expr *> &Set,
+                        llvm::ImmutableSet<const Expr *>::Factory &F,
+                        const Expr *E) {
+  Set = F.add(Set, LookThroughExpr(E));
 }
 
 void TransferFunctions::Visit(Stmt *S) {
@@ -215,8 +214,8 @@ void TransferFunctions::Visit(Stmt *S) {
 
   StmtVisitor<TransferFunctions>::Visit(S);
 
-  if (isa<Expr>(S)) {
-    val.liveStmts = LV.SSetFact.remove(val.liveStmts, S);
+  if (const auto *E = dyn_cast<Expr>(S)) {
+    val.liveExprs = LV.ESetFact.remove(val.liveExprs, E);
   }
 
   // Mark all children expressions live.
@@ -233,7 +232,7 @@ void TransferFunctions::Visit(Stmt *S) {
       // Include the implicit "this" pointer as being live.
       CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S);
       if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) {
-        AddLiveStmt(val.liveStmts, LV.SSetFact, ImplicitObj);
+        AddLiveExpr(val.liveExprs, LV.ESetFact, ImplicitObj);
       }
       break;
     }
@@ -250,7 +249,7 @@ void TransferFunctions::Visit(Stmt *S) {
       if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) {
         for (const VariableArrayType* VA = FindVA(VD->getType());
              VA != nullptr; VA = FindVA(VA->getElementType())) {
-          AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr());
+          AddLiveExpr(val.liveExprs, LV.ESetFact, VA->getSizeExpr());
         }
       }
       break;
@@ -263,7 +262,7 @@ void TransferFunctions::Visit(Stmt *S) {
       if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
         child = OV->getSourceExpr();
       child = child->IgnoreParens();
-      val.liveStmts = LV.SSetFact.add(val.liveStmts, child);
+      val.liveExprs = LV.ESetFact.add(val.liveExprs, child);
       return;
     }
 
@@ -284,36 +283,39 @@ void TransferFunctions::Visit(Stmt *S) {
       // If one of the branches is an expression rather than a compound
       // statement, it will be bad if we mark it as live at the terminator
       // of the if-statement (i.e., immediately after the condition expression).
-      AddLiveStmt(val.liveStmts, LV.SSetFact, cast<IfStmt>(S)->getCond());
+      AddLiveExpr(val.liveExprs, LV.ESetFact, cast<IfStmt>(S)->getCond());
       return;
     }
     case Stmt::WhileStmtClass: {
       // If the loop body is an expression rather than a compound statement,
       // it will be bad if we mark it as live at the terminator of the loop
       // (i.e., immediately after the condition expression).
-      AddLiveStmt(val.liveStmts, LV.SSetFact, cast<WhileStmt>(S)->getCond());
+      AddLiveExpr(val.liveExprs, LV.ESetFact, cast<WhileStmt>(S)->getCond());
       return;
     }
     case Stmt::DoStmtClass: {
       // If the loop body is an expression rather than a compound statement,
       // it will be bad if we mark it as live at the terminator of the loop
       // (i.e., immediately after the condition expression).
-      AddLiveStmt(val.liveStmts, LV.SSetFact, cast<DoStmt>(S)->getCond());
+      AddLiveExpr(val.liveExprs, LV.ESetFact, cast<DoStmt>(S)->getCond());
       return;
     }
     case Stmt::ForStmtClass: {
       // If the loop body is an expression rather than a compound statement,
       // it will be bad if we mark it as live at the terminator of the loop
       // (i.e., immediately after the condition expression).
-      AddLiveStmt(val.liveStmts, LV.SSetFact, cast<ForStmt>(S)->getCond());
+      AddLiveExpr(val.liveExprs, LV.ESetFact, cast<ForStmt>(S)->getCond());
       return;
     }
 
   }
 
+  // HACK + FIXME: What is this? One could only guess that this is an attempt to
+  // fish for live values, for example, arguments from a call expression.
+  // Maybe we could take inspiration from UninitializedVariable analysis?
   for (Stmt *Child : S->children()) {
-    if (Child)
-      AddLiveStmt(val.liveStmts, LV.SSetFact, Child);
+    if (const auto *E = dyn_cast_or_null<Expr>(Child))
+      AddLiveExpr(val.liveExprs, LV.ESetFact, E);
   }
 }
 
@@ -416,7 +418,7 @@ VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE)
   const Expr *subEx = UE->getArgumentExpr();
   if (subEx->getType()->isVariableArrayType()) {
     assert(subEx->isLValue());
-    val.liveStmts = LV.SSetFact.add(val.liveStmts, subEx->IgnoreParens());
+    val.liveExprs = LV.ESetFact.add(val.liveExprs, subEx->IgnoreParens());
   }
 }
 
@@ -613,19 +615,19 @@ void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) {
   llvm::errs() << "\n";
 }
 
-void LiveVariables::dumpStmtLiveness(const SourceManager &M) {
-  getImpl(impl).dumpStmtLiveness(M);
+void LiveVariables::dumpExprLiveness(const SourceManager &M) {
+  getImpl(impl).dumpExprLiveness(M);
 }
 
-void LiveVariablesImpl::dumpStmtLiveness(const SourceManager &M) {
+void LiveVariablesImpl::dumpExprLiveness(const SourceManager &M) {
   // Don't iterate over blockEndsToLiveness directly because it's not sorted.
-  for (auto I : *analysisContext.getCFG()) {
+  for (const CFGBlock *B : *analysisContext.getCFG()) {
 
-    llvm::errs() << "\n[ B" << I->getBlockID()
-                 << " (live statements at block exit) ]\n";
-    for (auto S : blocksEndToLiveness[I].liveStmts) {
+    llvm::errs() << "\n[ B" << B->getBlockID()
+                 << " (live expressions at block exit) ]\n";
+    for (const Expr *E : blocksEndToLiveness[B].liveExprs) {
       llvm::errs() << "\n";
-      S->dump();
+      E->dump();
     }
     llvm::errs() << "\n";
   }

diff  --git a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 03b7cbd1c833..7cdd78b8adfb 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -131,21 +131,21 @@ bool ento::shouldRegisterLiveVariablesDumper(const CheckerManager &mgr) {
 //===----------------------------------------------------------------------===//
 
 namespace {
-class LiveStatementsDumper : public Checker<check::ASTCodeBody> {
+class LiveExpressionsDumper : public Checker<check::ASTCodeBody> {
 public:
   void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
                         BugReporter &BR) const {
     if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D))
-      L->dumpStmtLiveness(Mgr.getSourceManager());
+      L->dumpExprLiveness(Mgr.getSourceManager());
   }
 };
 }
 
-void ento::registerLiveStatementsDumper(CheckerManager &mgr) {
-  mgr.registerChecker<LiveStatementsDumper>();
+void ento::registerLiveExpressionsDumper(CheckerManager &mgr) {
+  mgr.registerChecker<LiveExpressionsDumper>();
 }
 
-bool ento::shouldRegisterLiveStatementsDumper(const CheckerManager &mgr) {
+bool ento::shouldRegisterLiveExpressionsDumper(const CheckerManager &mgr) {
   return true;
 }
 

diff  --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp
index cba20b967b6f..ee7474592528 100644
--- a/clang/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp
@@ -191,19 +191,15 @@ EnvironmentManager::removeDeadBindings(Environment Env,
              F.getTreeFactory());
 
   // Iterate over the block-expr bindings.
-  for (Environment::iterator I = Env.begin(), E = Env.end();
-       I != E; ++I) {
+  for (Environment::iterator I = Env.begin(), End = Env.end(); I != End; ++I) {
     const EnvironmentEntry &BlkExpr = I.getKey();
     const SVal &X = I.getData();
 
-    const bool IsBlkExprLive =
-        SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext());
+    const Expr *E = dyn_cast<Expr>(BlkExpr.getStmt());
+    if (!E)
+      continue;
 
-    assert((isa<Expr>(BlkExpr.getStmt()) || !IsBlkExprLive) &&
-           "Only Exprs can be live, LivenessAnalysis argues about the liveness "
-           "of *values*!");
-
-    if (IsBlkExprLive) {
+    if (SymReaper.isLive(E, BlkExpr.getLocationContext())) {
       // Copy the binding to the new map.
       EBMapRef = EBMapRef.add(BlkExpr, X);
 

diff  --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 700f91aed610..79a8eef30576 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -489,7 +489,7 @@ bool SymbolReaper::isLive(SymbolRef sym) {
 }
 
 bool
-SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
+SymbolReaper::isLive(const Expr *ExprVal, const LocationContext *ELCtx) const {
   if (LCtx == nullptr)
     return false;
 

diff  --git a/clang/test/Analysis/live-stmts.cpp b/clang/test/Analysis/live-stmts.cpp
index 1b8a750c5e5c..16954f30129f 100644
--- a/clang/test/Analysis/live-stmts.cpp
+++ b/clang/test/Analysis/live-stmts.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -w -analyzer-checker=debug.DumpLiveStmts %s 2>&1\
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=debug.DumpLiveExprs %s 2>&1\
 // RUN:   | FileCheck %s
 
 int coin();
@@ -7,13 +7,24 @@ int coin();
 int testThatDumperWorks(int x, int y, int z) {
   return x ? y : z;
 }
-// CHECK: [ B0 (live statements at block exit) ]
+
+// [B5 (ENTRY)]
+//    |
+//    V
+// [B4 (x)] ? [B2 (y)] : [B3 (z)]
+//                \        /
+//                 ---|----
+//                    V
+//                   [B1] --> [B0 (EXIT)]
+//                  return
+
+// CHECK: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B1 (live statements at block exit) ]
+// CHECK: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B2 (live statements at block exit) ]
+// CHECK: [ B2 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-NEXT: DeclRefExpr {{.*}} 'y' 'int'
 // CHECK-EMPTY:
@@ -24,7 +35,7 @@ int testThatDumperWorks(int x, int y, int z) {
 // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'x' 'int'
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B3 (live statements at block exit) ]
+// CHECK: [ B3 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-NEXT: DeclRefExpr {{.*}} 'y' 'int'
 // CHECK-EMPTY:
@@ -33,7 +44,7 @@ int testThatDumperWorks(int x, int y, int z) {
 // CHECK-NEXT: ImplicitCastExpr {{.*}} <IntegralToBoolean>
 // CHECK-NEXT: `-ImplicitCastExpr {{.*}} <LValueToRValue>
 // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'x' 'int'
-// CHECK: [ B4 (live statements at block exit) ]
+// CHECK: [ B4 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-NEXT: DeclRefExpr {{.*}} 'y' 'int'
 // CHECK-EMPTY:
@@ -44,7 +55,7 @@ int testThatDumperWorks(int x, int y, int z) {
 // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'x' 'int'
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B5 (live statements at block exit) ]
+// CHECK: [ B5 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-NEXT: DeclRefExpr {{.*}} 'y' 'int'
 // CHECK-EMPTY:
@@ -61,22 +72,22 @@ void testIfBranchExpression(bool flag) {
       e;
   }
 }
-// CHECK: [ B0 (live statements at block exit) ]
+// CHECK: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B1 (live statements at block exit) ]
+// CHECK: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B2 (live statements at block exit) ]
+// CHECK: [ B2 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B3 (live statements at block exit) ]
+// CHECK: [ B3 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B4 (live statements at block exit) ]
+// CHECK: [ B4 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B5 (live statements at block exit) ]
+// CHECK: [ B5 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
 
@@ -89,22 +100,22 @@ void testWhileBodyExpression(bool flag) {
       e;
   }
 }
-// CHECK: [ B0 (live statements at block exit) ]
+// CHECK: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B1 (live statements at block exit) ]
+// CHECK: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B2 (live statements at block exit) ]
+// CHECK: [ B2 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B3 (live statements at block exit) ]
+// CHECK: [ B3 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B4 (live statements at block exit) ]
+// CHECK: [ B4 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B5 (live statements at block exit) ]
+// CHECK: [ B5 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
 
@@ -118,22 +129,22 @@ void testDoWhileBodyExpression(bool flag) {
     while (coin());
   }
 }
-// CHECK: [ B0 (live statements at block exit) ]
+// CHECK: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B1 (live statements at block exit) ]
+// CHECK: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B2 (live statements at block exit) ]
+// CHECK: [ B2 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B3 (live statements at block exit) ]
+// CHECK: [ B3 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B4 (live statements at block exit) ]
+// CHECK: [ B4 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B5 (live statements at block exit) ]
+// CHECK: [ B5 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
 
@@ -146,22 +157,39 @@ void testForBodyExpression(bool flag) {
       e;
   }
 }
-// CHECK: [ B0 (live statements at block exit) ]
+// CHECK: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B1 (live statements at block exit) ]
+// CHECK: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B2 (live statements at block exit) ]
+// CHECK: [ B2 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B3 (live statements at block exit) ]
+// CHECK: [ B3 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B4 (live statements at block exit) ]
+// CHECK: [ B4 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK: [ B5 (live statements at block exit) ]
+// CHECK: [ B5 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
 
+void clang_analyzer_eval(bool);
+
+void test_lambda_refcapture() {
+  int a = 6;
+  [&](int &a) { a = 42; }(a);
+  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+}
+
+// CHECK: [ B0 (live expressions at block exit) ]
+// CHECK-EMPTY:
+// CHECK-EMPTY:
+// CHECK-NEXT: [ B1 (live expressions at block exit) ]
+// CHECK-EMPTY:
+// CHECK-EMPTY:
+// CHECK-NEXT: [ B2 (live expressions at block exit) ]
+// CHECK-EMPTY:
+// CHECK-EMPTY:

diff  --git a/clang/test/Analysis/live-stmts.mm b/clang/test/Analysis/live-stmts.mm
index a6ddd03ca5d8..8acdd77149eb 100644
--- a/clang/test/Analysis/live-stmts.mm
+++ b/clang/test/Analysis/live-stmts.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_analyze_cc1 -w -fblocks %s \
-// RUN:   -analyzer-checker=debug.DumpLiveStmts \
+// RUN:   -analyzer-checker=debug.DumpLiveExprs \
 // RUN:   2>&1 | FileCheck %s
 
 @interface Item
@@ -18,25 +18,25 @@ @interface Collection
 public:
   RAII(Blk blk): blk(blk) {}
 
-// CHECK: [ B0 (live statements at block exit) ]
+// CHECK: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B1 (live statements at block exit) ]
+// CHECK-NEXT: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B2 (live statements at block exit) ]
+// CHECK-NEXT: [ B2 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
 
   ~RAII() { blk(); }
 
-// CHECK-NEXT: [ B0 (live statements at block exit) ]
+// CHECK-NEXT: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B1 (live statements at block exit) ]
+// CHECK-NEXT: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B2 (live statements at block exit) ]
+// CHECK-NEXT: [ B2 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
 };
@@ -45,57 +45,37 @@ void foo(Collection *coll) {
   RAII raii(^{});
   for (Item *item in coll) {}
 }
-// CHECK-NEXT: [ B0 (live statements at block exit) ]
+// CHECK-NEXT: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B1 (live statements at block exit) ]
+// CHECK-NEXT: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B2 (live statements at block exit) ]
-// CHECK-EMPTY:
-// CHECK-NEXT: DeclStmt {{.*}}
-// CHECK-NEXT: `-VarDecl {{.*}}  item 'Item *'
+// CHECK-NEXT: [ B2 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'Collection *' <LValueToRValue>
 // CHECK-NEXT: `-DeclRefExpr {{.*}} 'Collection *' lvalue ParmVar {{.*}} 'coll' 'Collection *'
 // CHECK-EMPTY:
-// CHECK-NEXT: CompoundStmt {{.*}}
-// CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B3 (live statements at block exit) ]
-// CHECK-EMPTY:
-// CHECK-NEXT: DeclStmt {{.*}}
-// CHECK-NEXT: `-VarDecl {{.*}}  item 'Item *'
+// CHECK-NEXT: [ B3 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'Collection *' <LValueToRValue>
 // CHECK-NEXT: `-DeclRefExpr {{.*}} 'Collection *' lvalue ParmVar {{.*}} 'coll' 'Collection *'
 // CHECK-EMPTY:
-// CHECK-NEXT: CompoundStmt {{.*}}
-// CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B4 (live statements at block exit) ]
-// CHECK-EMPTY:
-// CHECK-NEXT: DeclStmt {{.*}}
-// CHECK-NEXT: `-VarDecl {{.*}}  item 'Item *'
+// CHECK-NEXT: [ B4 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'Collection *' <LValueToRValue>
 // CHECK-NEXT: `-DeclRefExpr {{.*}} 'Collection *' lvalue ParmVar {{.*}} 'coll' 'Collection *'
 // CHECK-EMPTY:
-// CHECK-NEXT: CompoundStmt {{.*}}
-// CHECK-EMPTY:
-// CHECK-EMPTY:
-// CHECK-NEXT: [ B5 (live statements at block exit) ]
-// CHECK-EMPTY:
-// CHECK-NEXT: DeclStmt {{.*}}
-// CHECK-NEXT: `-VarDecl {{.*}}  item 'Item *'
 // CHECK-EMPTY:
-// CHECK-NEXT: CompoundStmt {{.*}}
+// CHECK-NEXT: [ B5 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B0 (live statements at block exit) ]
+// CHECK-NEXT: [ B0 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
-// CHECK-NEXT: [ B1 (live statements at block exit) ]
+// CHECK-NEXT: [ B1 (live expressions at block exit) ]
 // CHECK-EMPTY:
 // CHECK-EMPTY:
 


        


More information about the cfe-commits mailing list