>From ad6c2f196ee3b9b22dfa136169672b88a198f962 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erikjv@me.com>
Date: Thu, 12 Jan 2012 15:24:41 +0100
Subject: [PATCH] [CFG] Partial fix for PR 11645: put destructor calls before
 a return statement.

---
 lib/Analysis/CFG.cpp                        |   16 ++++++--
 test/Analysis/auto-obj-dtors-cfg-output.cpp |   56 +++++++++++++--------------
 2 files changed, 39 insertions(+), 33 deletions(-)

diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 4ccbf59..5ff3783 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -1607,12 +1607,20 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
   Block = createBlock(false);
 
   // The Exit block is the only successor.
-  addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
   addSuccessor(Block, &cfg->getExit());
 
-  // Add the return statement to the block.  This may create new blocks if R
-  // contains control-flow (short-circuit operations).
-  return VisitStmt(R, AddStmtChoice::AlwaysAdd);
+  // First add the return statement to the block.
+  AddStmtChoice asc(AddStmtChoice::AlwaysAdd);
+  if (asc.alwaysAdd(*this, R))
+    appendStmt(Block, R);
+
+  // Then add the automatic destructors, so they appear before the return in the
+  // CFG.
+  addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
+
+  // Lastly, add the children of the return statement to the block. This may
+  // create new blocks if R contains control-flow (short-circuit operations).
+  return VisitChildren(R);
 }
 
 CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
diff --git a/test/Analysis/auto-obj-dtors-cfg-output.cpp b/test/Analysis/auto-obj-dtors-cfg-output.cpp
index 2402e00..4c0df4f 100644
--- a/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -216,9 +216,9 @@ void test_catch_copy() {
 // CHECK:    Preds (1): B3
 // CHECK:    Succs (1): B0
 // CHECK:  [B2]
-// CHECK:    1: return;
-// CHECK:    2: [B3.4].~A() (Implicit destructor)
-// CHECK:    3: [B3.2].~A() (Implicit destructor)
+// CHECK:    1: [B3.4].~A() (Implicit destructor)
+// CHECK:    2: [B3.2].~A() (Implicit destructor)
+// CHECK:    3: return;
 // CHECK:    Preds (1): B3
 // CHECK:    Succs (1): B0
 // CHECK:  [B3]
@@ -341,10 +341,10 @@ void test_catch_copy() {
 // CHECK:    Preds (1): B4
 // CHECK:    Succs (1): B1
 // CHECK:  [B3]
-// CHECK:    1: return;
-// CHECK:    2: [B4.2].~A() (Implicit destructor)
-// CHECK:    3: [B8.6].~A() (Implicit destructor)
-// CHECK:    4: [B8.2].~A() (Implicit destructor)
+// CHECK:    1: [B4.2].~A() (Implicit destructor)
+// CHECK:    2: [B8.6].~A() (Implicit destructor)
+// CHECK:    3: [B8.2].~A() (Implicit destructor)
+// CHECK:    4: return;
 // CHECK:    Preds (1): B4
 // CHECK:    Succs (1): B0
 // CHECK:  [B4]
@@ -363,10 +363,10 @@ void test_catch_copy() {
 // CHECK:    Preds (1): B7
 // CHECK:    Succs (1): B1
 // CHECK:  [B6]
-// CHECK:    1: return;
-// CHECK:    2: [B7.2].~A() (Implicit destructor)
-// CHECK:    3: [B8.6].~A() (Implicit destructor)
-// CHECK:    4: [B8.2].~A() (Implicit destructor)
+// CHECK:    1: [B7.2].~A() (Implicit destructor)
+// CHECK:    2: [B8.6].~A() (Implicit destructor)
+// CHECK:    3: [B8.2].~A() (Implicit destructor)
+// CHECK:    4: return;
 // CHECK:    Preds (1): B7
 // CHECK:    Succs (1): B0
 // CHECK:  [B7]
@@ -469,10 +469,10 @@ void test_catch_copy() {
 // CHECK:    Preds (1): B6
 // CHECK:    Succs (1): B3
 // CHECK:  [B5]
-// CHECK:    1: return;
-// CHECK:    2: [B10.2].~A() (Implicit destructor)
-// CHECK:    3: [B2.4].~A() (Implicit destructor)
-// CHECK:    4: [B11.2].~A() (Implicit destructor)
+// CHECK:    1: [B10.2].~A() (Implicit destructor)
+// CHECK:    2: [B2.4].~A() (Implicit destructor)
+// CHECK:    3: [B11.2].~A() (Implicit destructor)
+// CHECK:    4: return;
 // CHECK:    Preds (1): B6
 // CHECK:    Succs (1): B0
 // CHECK:  [B6]
@@ -555,9 +555,9 @@ void test_catch_copy() {
 // CHECK:    Preds (1): B5
 // CHECK:    Succs (1): B2
 // CHECK:  [B4]
-// CHECK:    1: return;
-// CHECK:    2: [B9.2].~A() (Implicit destructor)
-// CHECK:    3: [B11.2].~A() (Implicit destructor)
+// CHECK:    1: [B9.2].~A() (Implicit destructor)
+// CHECK:    2: [B11.2].~A() (Implicit destructor)
+// CHECK:    3: return;
 // CHECK:    Preds (1): B5
 // CHECK:    Succs (1): B0
 // CHECK:  [B5]
@@ -668,10 +668,10 @@ void test_catch_copy() {
 // CHECK:    Preds (1): B6
 // CHECK:    Succs (1): B3
 // CHECK:  [B5]
-// CHECK:    1: return;
-// CHECK:    2: [B8.2].~A() (Implicit destructor)
-// CHECK:    3: [B2.6].~A() (Implicit destructor)
-// CHECK:    4: [B2.2].~A() (Implicit destructor)
+// CHECK:    1: [B8.2].~A() (Implicit destructor)
+// CHECK:    2: [B2.6].~A() (Implicit destructor)
+// CHECK:    3: [B2.2].~A() (Implicit destructor)
+// CHECK:    4: return;
 // CHECK:    Preds (1): B6
 // CHECK:    Succs (1): B0
 // CHECK:  [B6]
@@ -771,11 +771,11 @@ void test_catch_copy() {
 // CHECK:    Preds (1): B6
 // CHECK:    Succs (1): B3
 // CHECK:  [B5]
-// CHECK:    1: return;
-// CHECK:    2: [B10.2].~A() (Implicit destructor)
-// CHECK:    3: [B2.4].~A() (Implicit destructor)
-// CHECK:    4: [B11.4].~A() (Implicit destructor)
-// CHECK:    5: [B11.2].~A() (Implicit destructor)
+// CHECK:    1: [B10.2].~A() (Implicit destructor)
+// CHECK:    2: [B2.4].~A() (Implicit destructor)
+// CHECK:    3: [B11.4].~A() (Implicit destructor)
+// CHECK:    4: [B11.2].~A() (Implicit destructor)
+// CHECK:    5: return;
 // CHECK:    Preds (1): B6
 // CHECK:    Succs (1): B0
 // CHECK:  [B6]
@@ -840,5 +840,3 @@ void test_catch_copy() {
 // CHECK:    Succs (1): B0
 // CHECK:  [B0 (EXIT)]
 // CHECK:    Preds (3): B2 B1 B3
-
-
-- 
1.7.5.4

