Change subexpressions to be visited in the CFG from left-to-right.
authorTed Kremenek <kremenek@apple.com>
Tue, 5 Feb 2013 22:00:19 +0000 (22:00 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 5 Feb 2013 22:00:19 +0000 (22:00 +0000)
This is a more natural order of evaluation, and it is very important
for visualization in the static analyzer.  Within Xcode, the arrows
will not jump from right to left, which looks very visually jarring.
It also provides a more natural location for dataflow-based diagnostics.

Along the way, we found a case in the analyzer diagnostics where we
needed to indicate that a variable was "captured" by a block.

-fsyntax-only timings on sqlite3.c show no visible performance change,
although this is just one test case.

Fixes <rdar://problem/13016513>

llvm-svn: 174447

clang/include/clang/AST/Expr.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
clang/lib/Analysis/CFG.cpp
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
clang/lib/StaticAnalyzer/Core/MemRegion.cpp
clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
clang/test/Analysis/unix-fns.c
clang/test/Sema/warn-unreachable.c

index 09ca275..598f189 100644 (file)
@@ -2207,6 +2207,15 @@ public:
     return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs();
   }
 
+  /// This method provides fast access to all the subexpressions of
+  /// a CallExpr without going through the slower virtual child_iterator
+  /// interface.  This provides efficient reverse iteration of the
+  /// subexpressions.  This is currently used for CFG construction.
+  ArrayRef<Stmt*> getRawSubExprs() {
+    return ArrayRef<Stmt*>(SubExprs,
+                           getNumPreArgs() + PREARGS_START + getNumArgs());
+  }
+
   /// getNumCommas - Return the number of commas that must have been present in
   /// this function call.
   unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
index b0a44e2..59225cb 100644 (file)
@@ -662,6 +662,10 @@ public:
       return *this;
     }
   };
+
+  /// Return the original region for a captured region, if
+  /// one exists.
+  const VarRegion *getOriginalRegion(const VarRegion *VR) const;
       
   referenced_vars_iterator referenced_vars_begin() const;
   referenced_vars_iterator referenced_vars_end() const;  
index cd0ff0a..1cbaaee 100644 (file)
@@ -233,6 +233,43 @@ public:
   }
 };
 
+class reverse_children {
+  llvm::SmallVector<Stmt *, 12> childrenBuf;
+  ArrayRef<Stmt*> children;
+public:
+  reverse_children(Stmt *S);
+
+  typedef ArrayRef<Stmt*>::reverse_iterator iterator;
+  iterator begin() const { return children.rbegin(); }
+  iterator end() const { return children.rend(); }
+};
+
+
+reverse_children::reverse_children(Stmt *S) {
+  if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+    children = CE->getRawSubExprs();
+    return;
+  }
+  switch (S->getStmtClass()) {
+    case Stmt::InitListExprClass: {
+      InitListExpr *IE = cast<InitListExpr>(S);
+      children = llvm::makeArrayRef(reinterpret_cast<Stmt**>(IE->getInits()),
+                                    IE->getNumInits());
+      return;
+    }
+    default:
+      break;
+  }
+
+  // Default case for all other statements.
+  for (Stmt::child_range I = S->children(); I; ++I) {
+    childrenBuf.push_back(*I);
+  }
+
+  // This needs to be done *after* childrenBuf has been populated.
+  children = childrenBuf;
+}
+
 /// CFGBuilder - This class implements CFG construction from an AST.
 ///   The builder is stateful: an instance of the builder should be used to only
 ///   construct a single CFG.
@@ -1166,14 +1203,19 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
 }
 
 /// VisitChildren - Visit the children of a Stmt.
-CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) {
-  CFGBlock *lastBlock = Block;
-  for (Stmt::child_range I = Terminator->children(); I; ++I)
-    if (Stmt *child = *I)
-      if (CFGBlock *b = Visit(child))
-        lastBlock = b;
+CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
+  CFGBlock *B = Block;
 
-  return lastBlock;
+  // Visit the children in their reverse order so that they appear in
+  // left-to-right (natural) order in the CFG.
+  reverse_children RChildren(S);
+  for (reverse_children::iterator I = RChildren.begin(), E = RChildren.end();
+       I != E; ++I) {
+    if (Stmt *Child = *I)
+      if (CFGBlock *R = Visit(Child))
+        B = R;
+  }
+  return B;
 }
 
 CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
@@ -3093,19 +3135,14 @@ tryAgain:
 
 CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) {
   // When visiting children for destructors we want to visit them in reverse
-  // order. Because there's no reverse iterator for children must to reverse
-  // them in helper vector.
-  typedef SmallVector<Stmt *, 4> ChildrenVect;
-  ChildrenVect ChildrenRev;
-  for (Stmt::child_range I = E->children(); I; ++I) {
-    if (*I) ChildrenRev.push_back(*I);
-  }
-
+  // order that they will appear in the CFG.  Because the CFG is built
+  // bottom-up, this means we visit them in their natural order, which
+  // reverses them in the CFG.
   CFGBlock *B = Block;
-  for (ChildrenVect::reverse_iterator I = ChildrenRev.rbegin(),
-      L = ChildrenRev.rend(); I != L; ++I) {
-    if (CFGBlock *R = VisitForTemporaryDtors(*I))
-      B = R;
+  for (Stmt::child_range I = E->children(); I; ++I) {
+    if (Stmt *Child = *I)
+      if (CFGBlock *R = VisitForTemporaryDtors(Child))
+        B = R;
   }
   return B;
 }
index 3aa3515..17dd772 100644 (file)
@@ -433,42 +433,65 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
   llvm::raw_svector_ostream os(sbuf);
 
   if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) {
-    if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
-
-      if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
-        os << "Variable '" << *VR->getDecl() << "' ";
+    const Stmt *S = PS->getStmt();
+    const char *action = 0;
+    const DeclStmt *DS = dyn_cast<DeclStmt>(S);
+    const VarRegion *VR = dyn_cast<VarRegion>(R);
+
+    if (DS) {
+      action = "initialized to ";
+    } else if (isa<BlockExpr>(S)) {
+      action = "captured by block as ";
+      if (VR) {
+        // See if we can get the BlockVarRegion.
+        ProgramStateRef State = StoreSite->getState();
+        SVal V = State->getSVal(S, PS->getLocationContext());
+        if (const BlockDataRegion *BDR =
+              dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
+          if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
+            V = State->getSVal(OriginalR);
+            BR.addVisitor(new FindLastStoreBRVisitor(V, OriginalR));
+          }
+        }
       }
-      else
-        return NULL;
+    }
+
+    if (action) {
+      if (!R)
+        return 0;
+
+      os << "Variable '" << *VR->getDecl() << "' ";
 
       if (isa<loc::ConcreteInt>(V)) {
         bool b = false;
         if (R->isBoundable()) {
           if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
             if (TR->getValueType()->isObjCObjectPointerType()) {
-              os << "initialized to nil";
+              os << action << "nil";
               b = true;
             }
           }
         }
 
         if (!b)
-          os << "initialized to a null pointer value";
+          os << action << "a null pointer value";
       }
       else if (isa<nonloc::ConcreteInt>(V)) {
-        os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
+        os << action << cast<nonloc::ConcreteInt>(V).getValue();
       }
-      else if (V.isUndef()) {
-        if (isa<VarRegion>(R)) {
-          const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
-          if (VD->getInit())
-            os << "initialized to a garbage value";
-          else
-            os << "declared without an initial value";
+      else if (DS) {
+        if (V.isUndef()) {
+          if (isa<VarRegion>(R)) {
+            const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+            if (VD->getInit())
+              os << "initialized to a garbage value";
+            else
+              os << "declared without an initial value";
+          }
+        }
+        else {
+          os << "initialized here";
         }
-      }
-      else {
-        os << "initialized here";
       }
     }
   } else if (isa<CallEnter>(StoreSite->getLocation())) {
index 70bb965..687c7c0 100644 (file)
@@ -1302,3 +1302,13 @@ BlockDataRegion::referenced_vars_end() const {
   return BlockDataRegion::referenced_vars_iterator(Vec->end(),
                                                    VecOriginal->end());
 }
+
+const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
+  for (referenced_vars_iterator I = referenced_vars_begin(),
+                                E = referenced_vars_end();
+       I != E; ++I) {
+    if (I.getCapturedRegion() == R)
+      return I.getOriginalRegion();
+  }
+  return 0;
+}
index c884475..1ddccb7 100644 (file)
@@ -207,22 +207,22 @@ TestCtorInits::TestCtorInits()
 // CHECK:    14: int a = int(A().operator int()) + int(B().operator int());
 // CHECK:    15: ~B() (Temporary object destructor)
 // CHECK:    16: ~A() (Temporary object destructor)
-// CHECK:    17: A() (CXXConstructExpr, class A)
-// CHECK:    18: [B1.17] (BindTemporary)
-// CHECK:    19: [B1.18].operator int
-// CHECK:    20: [B1.19]()
-// CHECK:    21: [B1.20] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK:    22: int([B1.21]) (CXXFunctionalCastExpr, NoOp, int)
-// CHECK:    23: B() (CXXConstructExpr, class B)
-// CHECK:    24: [B1.23] (BindTemporary)
-// CHECK:    25: [B1.24].operator int
-// CHECK:    26: [B1.25]()
-// CHECK:    27: [B1.26] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK:    28: int([B1.27]) (CXXFunctionalCastExpr, NoOp, int)
-// CHECK:    29: [B1.22] + [B1.28]
-// CHECK:    30: foo
-// CHECK:    31: [B1.30] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
-// CHECK:    32: [B1.31]([B1.29])
+// CHECK:    17: foo
+// CHECK:    18: [B1.17] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK:    19: A() (CXXConstructExpr, class A)
+// CHECK:    20: [B1.19] (BindTemporary)
+// CHECK:    21: [B1.20].operator int
+// CHECK:    22: [B1.21]()
+// CHECK:    23: [B1.22] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK:    24: int([B1.23]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK:    25: B() (CXXConstructExpr, class B)
+// CHECK:    26: [B1.25] (BindTemporary)
+// CHECK:    27: [B1.26].operator int
+// CHECK:    28: [B1.27]()
+// CHECK:    29: [B1.28] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK:    30: int([B1.29]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK:    31: [B1.24] + [B1.30]
+// CHECK:    32: [B1.18]([B1.31])
 // CHECK:    33: ~B() (Temporary object destructor)
 // CHECK:    34: ~A() (Temporary object destructor)
 // CHECK:    35: int b;
@@ -242,11 +242,9 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Preds (1): B3
 // CHECK:     Succs (1): B1
 // CHECK:   [B3]
-// CHECK:     1: [B5.6] && [B4.5]
-// CHECK:     2: foo
-// CHECK:     3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
-// CHECK:     4: [B3.3]([B3.1])
-// CHECK:     T: [B5.6] && ...
+// CHECK:     1: [B5.8] && [B4.5]
+// CHECK:     2: [B5.3]([B3.1])
+// CHECK:     T: [B5.8] && ...
 // CHECK:     Preds (2): B4 B5
 // CHECK:     Succs (2): B2 B1
 // CHECK:   [B4]
@@ -259,12 +257,14 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Succs (1): B3
 // CHECK:   [B5]
 // CHECK:     1: ~A() (Temporary object destructor)
-// CHECK:     2: A() (CXXConstructExpr, class A)
-// CHECK:     3: [B5.2] (BindTemporary)
-// CHECK:     4: [B5.3].operator _Bool
-// CHECK:     5: [B5.4]()
-// CHECK:     6: [B5.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B5.6] && ...
+// CHECK:     2: foo
+// CHECK:     3: [B5.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
+// CHECK:     4: A() (CXXConstructExpr, class A)
+// CHECK:     5: [B5.4] (BindTemporary)
+// CHECK:     6: [B5.5].operator _Bool
+// CHECK:     7: [B5.6]()
+// CHECK:     8: [B5.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK:     T: [B5.8] && ...
 // CHECK:     Preds (2): B6 B7
 // CHECK:     Succs (2): B4 B3
 // CHECK:   [B6]
@@ -308,11 +308,9 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Preds (1): B3
 // CHECK:     Succs (1): B1
 // CHECK:   [B3]
-// CHECK:     1: [B5.6] || [B4.5]
-// CHECK:     2: foo
-// CHECK:     3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
-// CHECK:     4: [B3.3]([B3.1])
-// CHECK:     T: [B5.6] || ...
+// CHECK:     1: [B5.8] || [B4.5]
+// CHECK:     2: [B5.3]([B3.1])
+// CHECK:     T: [B5.8] || ...
 // CHECK:     Preds (2): B4 B5
 // CHECK:     Succs (2): B1 B2
 // CHECK:   [B4]
@@ -325,12 +323,14 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Succs (1): B3
 // CHECK:   [B5]
 // CHECK:     1: ~A() (Temporary object destructor)
-// CHECK:     2: A() (CXXConstructExpr, class A)
-// CHECK:     3: [B5.2] (BindTemporary)
-// CHECK:     4: [B5.3].operator _Bool
-// CHECK:     5: [B5.4]()
-// CHECK:     6: [B5.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B5.6] || ...
+// CHECK:     2: foo
+// CHECK:     3: [B5.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
+// CHECK:     4: A() (CXXConstructExpr, class A)
+// CHECK:     5: [B5.4] (BindTemporary)
+// CHECK:     6: [B5.5].operator _Bool
+// CHECK:     7: [B5.6]()
+// CHECK:     8: [B5.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK:     T: [B5.8] || ...
 // CHECK:     Preds (2): B6 B7
 // CHECK:     Succs (2): B3 B4
 // CHECK:   [B6]
@@ -370,17 +370,17 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Preds (2): B2 B3
 // CHECK:     Succs (1): B0
 // CHECK:   [B2]
-// CHECK:     1: 0
-// CHECK:     2: foo
-// CHECK:     3: [B2.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
-// CHECK:     4: [B2.3]([B2.1])
+// CHECK:     1: foo
+// CHECK:     2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK:     3: 0
+// CHECK:     4: [B2.2]([B2.3])
 // CHECK:     Preds (1): B4
 // CHECK:     Succs (1): B1
 // CHECK:   [B3]
-// CHECK:     1: 0
-// CHECK:     2: foo
-// CHECK:     3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
-// CHECK:     4: [B3.3]([B3.1])
+// CHECK:     1: foo
+// CHECK:     2: [B3.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK:     3: 0
+// CHECK:     4: [B3.2]([B3.3])
 // CHECK:     Preds (1): B4
 // CHECK:     Succs (1): B1
 // CHECK:   [B4]
@@ -474,13 +474,11 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Preds (1): B4
 // CHECK:     Succs (1): B1
 // CHECK:   [B4]
-// CHECK:     1: [B7.6] ? [B5.6] : [B6.15]
+// CHECK:     1: [B7.8] ? [B5.6] : [B6.15]
 // CHECK:     2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B4.2]
-// CHECK:     4: foo
-// CHECK:     5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK:     6: [B4.5]([B4.3])
-// CHECK:     T: [B7.6] ? ... : ...
+// CHECK:     4: [B7.3]([B4.3])
+// CHECK:     T: [B7.8] ? ... : ...
 // CHECK:     Preds (2): B5 B6
 // CHECK:     Succs (2): B2 B3
 // CHECK:   [B5]
@@ -512,12 +510,14 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Succs (1): B4
 // CHECK:   [B7]
 // CHECK:     1: ~B() (Temporary object destructor)
-// CHECK:     2: B() (CXXConstructExpr, class B)
-// CHECK:     3: [B7.2] (BindTemporary)
-// CHECK:     4: [B7.3].operator _Bool
-// CHECK:     5: [B7.4]()
-// CHECK:     6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B7.6] ? ... : ...
+// CHECK:     2: foo
+// CHECK:     3: [B7.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK:     4: B() (CXXConstructExpr, class B)
+// CHECK:     5: [B7.4] (BindTemporary)
+// CHECK:     6: [B7.5].operator _Bool
+// CHECK:     7: [B7.6]()
+// CHECK:     8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK:     T: [B7.8] ? ... : ...
 // CHECK:     Preds (2): B8 B9
 // CHECK:     Succs (2): B5 B6
 // CHECK:   [B8]
@@ -647,17 +647,15 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Preds (1): B4
 // CHECK:     Succs (1): B1
 // CHECK:   [B4]
-// CHECK:     1: [B7.3] ?: [B6.6]
+// CHECK:     1: [B7.5] ?: [B6.6]
 // CHECK:     2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B4.2]
-// CHECK:     4: foo
-// CHECK:     5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK:     6: [B4.5]([B4.3])
-// CHECK:     T: [B7.6] ? ... : ...
+// CHECK:     4: [B7.3]([B4.3])
+// CHECK:     T: [B7.8] ? ... : ...
 // CHECK:     Preds (2): B5 B6
 // CHECK:     Succs (2): B2 B3
 // CHECK:   [B5]
-// CHECK:     1: [B7.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK:     1: [B7.5] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     2: [B5.1]
 // CHECK:     3: [B5.2] (CXXConstructExpr, class A)
 // CHECK:     4: [B5.3] (BindTemporary)
@@ -674,12 +672,14 @@ TestCtorInits::TestCtorInits()
 // CHECK:     Succs (1): B4
 // CHECK:   [B7]
 // CHECK:     1: ~A() (Temporary object destructor)
-// CHECK:     2: A() (CXXConstructExpr, class A)
-// CHECK:     3: [B7.2] (BindTemporary)
-// CHECK:     4: [B7.3].operator _Bool
-// CHECK:     5: [B7.4]()
-// CHECK:     6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B7.6] ? ... : ...
+// CHECK:     2: foo
+// CHECK:     3: [B7.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK:     4: A() (CXXConstructExpr, class A)
+// CHECK:     5: [B7.4] (BindTemporary)
+// CHECK:     6: [B7.5].operator _Bool
+// CHECK:     7: [B7.6]()
+// CHECK:     8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK:     T: [B7.8] ? ... : ...
 // CHECK:     Preds (2): B9 B8
 // CHECK:     Succs (2): B5 B6
 // CHECK:   [B8]
@@ -745,13 +745,13 @@ TestCtorInits::TestCtorInits()
 // CHECK:     3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     4: [B1.3]
 // CHECK:     5: const A &a = A();
-// CHECK:     6: A() (CXXConstructExpr, class A)
-// CHECK:     7: [B1.6] (BindTemporary)
-// CHECK:     8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
-// CHECK:     9: [B1.8]
-// CHECK:    10: foo
-// CHECK:    11: [B1.10] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK:    12: [B1.11]([B1.9])
+// CHECK:     6: foo
+// CHECK:     7: [B1.6] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK:     8: A() (CXXConstructExpr, class A)
+// CHECK:     9: [B1.8] (BindTemporary)
+// CHECK:    10: [B1.9] (ImplicitCastExpr, NoOp, const class A)
+// CHECK:    11: [B1.10]
+// CHECK:    12: [B1.7]([B1.11])
 // CHECK:    13: ~A() (Temporary object destructor)
 // CHECK:    14: int b;
 // CHECK:    15: [B1.5].~A() (Implicit destructor)
@@ -787,15 +787,15 @@ TestCtorInits::TestCtorInits()
 // CHECK:     5: [B1.4] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     6: [B1.5]
 // CHECK:     7: const A &a = A::make();
-// CHECK:     8: A::make
-// CHECK:     9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
-// CHECK:    10: [B1.9]()
-// CHECK:    11: [B1.10] (BindTemporary)
-// CHECK:    12: [B1.11] (ImplicitCastExpr, NoOp, const class A)
-// CHECK:    13: [B1.12]
-// CHECK:    14: foo
-// CHECK:    15: [B1.14] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK:    16: [B1.15]([B1.13])
+// CHECK:     8: foo
+// CHECK:     9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK:    10: A::make
+// CHECK:    11: [B1.10] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
+// CHECK:    12: [B1.11]()
+// CHECK:    13: [B1.12] (BindTemporary)
+// CHECK:    14: [B1.13] (ImplicitCastExpr, NoOp, const class A)
+// CHECK:    15: [B1.14]
+// CHECK:    16: [B1.9]([B1.15])
 // CHECK:    17: ~A() (Temporary object destructor)
 // CHECK:    18: int b;
 // CHECK:    19: [B1.7].~A() (Implicit destructor)
index 9db5fa8..fd9b22d 100644 (file)
@@ -1418,12 +1418,12 @@ void test_inline_dispatch_once() {
 // CHECK-NEXT:          <array>
 // CHECK-NEXT:           <dict>
 // CHECK-NEXT:            <key>line</key><integer>190</integer>
-// CHECK-NEXT:            <key>col</key><integer>3</integer>
+// CHECK-NEXT:            <key>col</key><integer>24</integer>
 // CHECK-NEXT:            <key>file</key><integer>0</integer>
 // CHECK-NEXT:           </dict>
 // CHECK-NEXT:           <dict>
 // CHECK-NEXT:            <key>line</key><integer>190</integer>
-// CHECK-NEXT:            <key>col</key><integer>15</integer>
+// CHECK-NEXT:            <key>col</key><integer>24</integer>
 // CHECK-NEXT:            <key>file</key><integer>0</integer>
 // CHECK-NEXT:           </dict>
 // CHECK-NEXT:          </array>
@@ -1435,6 +1435,35 @@ void test_inline_dispatch_once() {
 // CHECK-NEXT:      <key>location</key>
 // CHECK-NEXT:      <dict>
 // CHECK-NEXT:       <key>line</key><integer>190</integer>
+// CHECK-NEXT:       <key>col</key><integer>24</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>ranges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:        <array>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>190</integer>
+// CHECK-NEXT:          <key>col</key><integer>24</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>194</integer>
+// CHECK-NEXT:          <key>col</key><integer>3</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:        </array>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:      <key>depth</key><integer>0</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Variable &apos;p&apos; captured by block as a null pointer value</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Variable &apos;p&apos; captured by block as a null pointer value</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>190</integer>
 // CHECK-NEXT:       <key>col</key><integer>3</integer>
 // CHECK-NEXT:       <key>file</key><integer>0</integer>
 // CHECK-NEXT:      </dict>
@@ -1739,6 +1768,69 @@ void test_inline_dispatch_once() {
 // CHECK-NEXT:      <string>Variable &apos;p&apos; initialized to a null pointer value</string>
 // CHECK-NEXT:     </dict>
 // CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>control</string>
+// CHECK-NEXT:      <key>edges</key>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>start</key>
+// CHECK-NEXT:          <array>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>200</integer>
+// CHECK-NEXT:            <key>col</key><integer>3</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>200</integer>
+// CHECK-NEXT:            <key>col</key><integer>5</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:          </array>
+// CHECK-NEXT:         <key>end</key>
+// CHECK-NEXT:          <array>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>201</integer>
+// CHECK-NEXT:            <key>col</key><integer>24</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:           <dict>
+// CHECK-NEXT:            <key>line</key><integer>201</integer>
+// CHECK-NEXT:            <key>col</key><integer>24</integer>
+// CHECK-NEXT:            <key>file</key><integer>0</integer>
+// CHECK-NEXT:           </dict>
+// CHECK-NEXT:          </array>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>kind</key><string>event</string>
+// CHECK-NEXT:      <key>location</key>
+// CHECK-NEXT:      <dict>
+// CHECK-NEXT:       <key>line</key><integer>201</integer>
+// CHECK-NEXT:       <key>col</key><integer>24</integer>
+// CHECK-NEXT:       <key>file</key><integer>0</integer>
+// CHECK-NEXT:      </dict>
+// CHECK-NEXT:      <key>ranges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:        <array>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>201</integer>
+// CHECK-NEXT:          <key>col</key><integer>24</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:         <dict>
+// CHECK-NEXT:          <key>line</key><integer>203</integer>
+// CHECK-NEXT:          <key>col</key><integer>3</integer>
+// CHECK-NEXT:          <key>file</key><integer>0</integer>
+// CHECK-NEXT:         </dict>
+// CHECK-NEXT:        </array>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:      <key>depth</key><integer>0</integer>
+// CHECK-NEXT:      <key>extended_message</key>
+// CHECK-NEXT:      <string>Variable &apos;p&apos; captured by block as a null pointer value</string>
+// CHECK-NEXT:      <key>message</key>
+// CHECK-NEXT:      <string>Variable &apos;p&apos; captured by block as a null pointer value</string>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <dict>
 // CHECK-NEXT:      <key>kind</key><string>event</string>
 // CHECK-NEXT:      <key>location</key>
 // CHECK-NEXT:      <dict>
index 2fbe1c7..fd74b5c 100644 (file)
@@ -80,8 +80,8 @@ void test2() {
     -           // expected-warning {{will never be executed}}
       halt();
   case 8:
-    i           // expected-warning {{will never be executed}}
-      +=
+    i
+      +=        // expected-warning {{will never be executed}}
       halt();
   case 9:
     halt()
@@ -93,8 +93,8 @@ void test2() {
   case 11: {
     int a[5];
     live(),
-      a[halt()  // expected-warning {{will never be executed}}
-        ];
+      a[halt()
+        ];      // expected-warning {{will never be executed}}
   }
   }
 }