]> granicus.if.org Git - clang/commitdiff
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>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174447 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 09ca2758fe89a3ac038e0facddc6ca4843bcffdb..598f18937f91b833a0d228216ba00528e75d4db9 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 b0a44e26fe20d807f48071c39a3fde27bd566292..59225cb150130ae948f4d983608256d61258f6b4 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 cd0ff0a4922ddbb33e7490825c6ddd5a2e1d7eec..1cbaaee4a1c7420b12a40c1937b21b59035b25c8 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 3aa351527f3ba2ae76d3ebbf14ffc133f3022efc..17dd772a688f6d7fe073f96c325007cbd042c314 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 70bb96585933c64bb522cf27da96e36d17222ee0..687c7c0188aae52e6f28906380894bedbc7728fd 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 c8844754bef8f6424bc85fe567d360a0786f5ca8..1ddccb704b132d8b1719169d4dff37b4a8191409 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 9db5fa8256cadabeb5fd1e3c6573a703ce36d801..fd9b22dae8af5c2d128e79a4aeb6a15de3fb877e 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 2fbe1c78eb21025659b2326bf4e2f90cc2ca8803..fd74b5c87175e5098c4d34aaf696dd60776548c8 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}}
   }
   }
 }