aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Analysis/CFG.cpp21
-rw-r--r--test/Analysis/dead-stores.cpp21
2 files changed, 42 insertions, 0 deletions
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 4c2ecb92f6..f43631c4d0 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -99,6 +99,7 @@ private:
CFGBlock *VisitCompoundStmt(CompoundStmt *C);
CFGBlock *VisitConditionalOperator(ConditionalOperator *C);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
+ CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
CFGBlock *VisitDeclStmt(DeclStmt *DS);
CFGBlock *VisitDeclSubExpr(Decl* D);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
@@ -319,6 +320,9 @@ tryAgain:
case Stmt::ObjCAtCatchStmtClass:
return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
+ case Stmt::CXXThrowExprClass:
+ return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
+
case Stmt::ObjCAtSynchronizedStmtClass:
return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
@@ -1262,6 +1266,23 @@ CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) {
return VisitStmt(S, true);
}
+CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) {
+ // If we were in the middle of a block we stop processing that block and
+ // reverse its statements.
+ if (Block && !FinishBlock(Block))
+ return 0;
+
+ // Create the new block.
+ Block = createBlock(false);
+
+ // The Exit block is the only successor.
+ Block->addSuccessor(&cfg->getExit());
+
+ // Add the statement to the block. This may create new blocks if S contains
+ // control-flow (short-circuit operations).
+ return VisitStmt(T, true);
+}
+
CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
// See if this is a known constant.
bool KnownTrue = false;
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
new file mode 100644
index 0000000000..ec7aebbc5b
--- /dev/null
+++ b/test/Analysis/dead-stores.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -analyze -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic-old-cast -analyzer-constraints=basic -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic-old-cast -analyzer-constraints=range -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -verify %s
+
+int j;
+void f1() {
+ int x = 4;
+
+ ++x; // expected-warning{{never read}}
+
+ switch (j) {
+ case 1:
+ throw 1;
+ (void)x;
+ break;
+ }
+}