summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/Analysis/CFG.cpp7
-rw-r--r--clang/test/Analysis/cfg.cpp37
2 files changed, 42 insertions, 2 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 5e03f4377d3..191c324b3c6 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1899,9 +1899,12 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
// Create the new block.
Block = createBlock(false);
- // The Exit block is the only successor.
addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
- addSuccessor(Block, &cfg->getExit());
+
+ // If the one of the destructors does not return, we already have the Exit
+ // block as a successor.
+ if (!Block->hasNoReturnElement())
+ addSuccessor(Block, &cfg->getExit());
// Add the return statement to the block. This may create new blocks if R
// contains control-flow (short-circuit operations).
diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp
index 243e1aed99c..660d1f26469 100644
--- a/clang/test/Analysis/cfg.cpp
+++ b/clang/test/Analysis/cfg.cpp
@@ -144,3 +144,40 @@ void test_deleteArraydtor() {
A *a = new A[5];
delete[] a;
}
+
+
+namespace NoReturnSingleSuccessor {
+ struct A {
+ A();
+ ~A();
+ };
+
+ struct B : public A {
+ B();
+ ~B() __attribute__((noreturn));
+ };
+
+// CHECK: ENTRY
+// CHECK: 1: 1
+// CHECK-NEXT: 2: return
+// CHECK-NEXT: ~B() (Implicit destructor)
+// CHECK-NEXT: Preds (1)
+// CHECK-NEXT: Succs (1): B0
+ int test1(int *x) {
+ B b;
+ if (x)
+ return 1;
+ }
+
+// CHECK: ENTRY
+// CHECK: 1: 1
+// CHECK-NEXT: 2: return
+// CHECK-NEXT: destructor
+// CHECK-NEXT: Preds (1)
+// CHECK-NEXT: Succs (1): B0
+ int test2(int *x) {
+ const A& a = B();
+ if (x)
+ return 1;
+ }
+}
OpenPOWER on IntegriCloud