tomasz-kaminski-sonarsource updated this revision to Diff 539470.
tomasz-kaminski-sonarsource marked 3 inline comments as done.
tomasz-kaminski-sonarsource added a comment.

Apply review suggestion and replaced make_scope_exit with SaveAndRestore that 
was already used
in file.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153273/new/

https://reviews.llvm.org/D153273

Files:
  clang/include/clang/Analysis/CFG.h
  clang/lib/Analysis/CFG.cpp
  clang/test/Analysis/auto-obj-dtors-cfg-output.cpp
  clang/test/Analysis/lifetime-cfg-output.cpp
  clang/test/Analysis/no-exit-cfg.c
  clang/test/Analysis/nonreturn-destructors-cfg-output.cpp
  clang/test/Analysis/scopes-cfg-output.cpp

Index: clang/test/Analysis/scopes-cfg-output.cpp
===================================================================
--- clang/test/Analysis/scopes-cfg-output.cpp
+++ clang/test/Analysis/scopes-cfg-output.cpp
@@ -674,30 +674,30 @@
   A f;
 }
 
-// CHECK:      [B8 (ENTRY)]
+// CHECK:      [B9 (ENTRY)]
 // CHECK-NEXT:   Succs (1): B7
 // CHECK:      [B1]
 // CHECK-NEXT:  l1:
 // CHECK-NEXT:   1:  (CXXConstructExpr, [B1.2], A)
 // CHECK-NEXT:   2: A c;
 // CHECK-NEXT:   3: [B1.2].~A() (Implicit destructor)
-// CHECK-NEXT:   4: [B6.5].~A() (Implicit destructor)
-// CHECK-NEXT:   5: [B6.3].~A() (Implicit destructor)
+// CHECK-NEXT:   4: [B6.4].~A() (Implicit destructor)
+// CHECK-NEXT:   5: [B6.2].~A() (Implicit destructor)
 // CHECK-NEXT:   6: [B7.3].~A() (Implicit destructor)
 // CHECK-NEXT:   7: CFGScopeEnd(a)
 // CHECK-NEXT:   Preds (2): B2 B3
 // CHECK-NEXT:   Succs (1): B0
 // CHECK:      [B2]
 // CHECK-NEXT:   1:  (CXXConstructExpr, [B2.2], A)
-// CHECK-NEXT:   2: A b;
+// CHECK-NEXT:   2: A nb;
 // CHECK-NEXT:   3: [B2.2].~A() (Implicit destructor)
-// CHECK-NEXT:   4: [B6.8].~A() (Implicit destructor)
-// CHECK-NEXT:   5: CFGScopeEnd(a)
+// CHECK-NEXT:   4: [B6.7].~A() (Implicit destructor)
+// CHECK-NEXT:   5: CFGScopeEnd(na)
 // CHECK-NEXT:   Preds (1): B4
 // CHECK-NEXT:   Succs (1): B1
 // CHECK:      [B3]
-// CHECK-NEXT:   1: [B6.8].~A() (Implicit destructor)
-// CHECK-NEXT:   2: CFGScopeEnd(a)
+// CHECK-NEXT:   1: [B6.7].~A() (Implicit destructor)
+// CHECK-NEXT:   2: CFGScopeEnd(na)
 // CHECK-NEXT:   T: goto l1;
 // CHECK-NEXT:   Preds (1): B4
 // CHECK-NEXT:   Succs (1): B1
@@ -708,33 +708,35 @@
 // CHECK-NEXT:   Preds (1): B6
 // CHECK-NEXT:   Succs (2): B3 B2
 // CHECK:      [B5]
-// CHECK-NEXT:   1: [B6.8].~A() (Implicit destructor)
-// CHECK-NEXT:   2: [B6.5].~A() (Implicit destructor)
-// CHECK-NEXT:   3: [B6.3].~A() (Implicit destructor)
-// CHECK-NEXT:   4: CFGScopeEnd(cb)
-// CHECK-NEXT:   T: goto l0;
 // CHECK-NEXT:   Preds (1): B6
-// CHECK-NEXT:   Succs (1): B6
+// CHECK-NEXT:   Succs (1): B8
 // CHECK:      [B6]
 // CHECK-NEXT:  l0:
-// CHECK-NEXT:   1: CFGScopeBegin(cb)
-// CHECK-NEXT:   2:  (CXXConstructExpr, [B6.3], A)
-// CHECK-NEXT:   3: A cb;
-// CHECK-NEXT:   4:  (CXXConstructExpr, [B6.5], A)
-// CHECK-NEXT:   5: A b;
-// CHECK-NEXT:   6: CFGScopeBegin(a)
-// CHECK-NEXT:   7:  (CXXConstructExpr, [B6.8], A)
-// CHECK-NEXT:   8: A a;
-// CHECK-NEXT:   9: UV
-// CHECK-NEXT:  10: [B6.9] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK-NEXT:   T: if [B6.10]
-// CHECK-NEXT:   Preds (2): B7 B5
+// CHECK-NEXT:   1:  (CXXConstructExpr, [B6.2], A)
+// CHECK-NEXT:   2: A cb;
+// CHECK-NEXT:   3:  (CXXConstructExpr, [B6.4], A)
+// CHECK-NEXT:   4: A b;
+// CHECK-NEXT:   5: CFGScopeBegin(na)
+// CHECK-NEXT:   6:  (CXXConstructExpr, [B6.7], A)
+// CHECK-NEXT:   7: A na;
+// CHECK-NEXT:   8: UV
+// CHECK-NEXT:   9: [B6.8] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:   T: if [B6.9]
+// CHECK-NEXT:   Preds (2): B7 B8
 // CHECK-NEXT:   Succs (2): B5 B4
 // CHECK:      [B7]
 // CHECK-NEXT:   1: CFGScopeBegin(a)
 // CHECK-NEXT:   2:  (CXXConstructExpr, [B7.3], A)
 // CHECK-NEXT:   3: A a;
-// CHECK-NEXT:   Preds (1): B8
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B6
+// CHECK:      [B8]
+// CHECK-NEXT:   1: [B6.7].~A() (Implicit destructor)
+// CHECK-NEXT:   2: CFGScopeEnd(na)
+// CHECK-NEXT:   3: [B6.4].~A() (Implicit destructor)
+// CHECK-NEXT:   4: [B6.2].~A() (Implicit destructor)
+// CHECK-NEXT:   T: goto l0;
+// CHECK-NEXT:   Preds (1): B5
 // CHECK-NEXT:   Succs (1): B6
 // CHECK:      [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
@@ -743,10 +745,10 @@
 l0:
   A cb;
   A b;
-  { A a;
+  { A na;
     if (UV) goto l0;
     if (UV) goto l1;
-    A b;
+    A nb;
   }
 l1:
   A c;
@@ -1168,3 +1170,184 @@
     }
   }
 }
+
+// CHECK:       [B4 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B3
+// CHECK:       [B1]
+// CHECK-NEXT:   label:
+// CHECK-NEXT:    1: CFGScopeEnd(n2t)
+// CHECK-NEXT:    2: CFGScopeEnd(n1t)
+// CHECK-NEXT:    3: [B3.3].~A() (Implicit destructor)
+// CHECK-NEXT:    4: CFGScopeEnd(a)
+// CHECK-NEXT:    Preds (2): B2 B3
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1: [B3.9].~A() (Implicit destructor)
+// CHECK-NEXT:    2: CFGScopeEnd(n2s)
+// CHECK-NEXT:    3: [B3.6].~A() (Implicit destructor)
+// CHECK-NEXT:    4: CFGScopeEnd(n1s)
+// CHECK-NEXT:    5: CFGScopeBegin(n1t)
+// CHECK-NEXT:    6: int n1t;
+// CHECK-NEXT:    7: CFGScopeBegin(n2t)
+// CHECK-NEXT:    8: int n2t;
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B3]
+// CHECK-NEXT:    1: CFGScopeBegin(a)
+// CHECK-NEXT:    2:  (CXXConstructExpr, [B3.3], A)
+// CHECK-NEXT:    3: A a;
+// CHECK-NEXT:    4: CFGScopeBegin(n1s)
+// CHECK-NEXT:    5:  (CXXConstructExpr, [B3.6], A)
+// CHECK-NEXT:    6: A n1s;
+// CHECK-NEXT:    7: CFGScopeBegin(n2s)
+// CHECK-NEXT:    8:  (CXXConstructExpr, [B3.9], A)
+// CHECK-NEXT:    9: A n2s;
+// CHECK-NEXT:   10: [B3.9].~A() (Implicit destructor)
+// CHECK-NEXT:   11: CFGScopeEnd(n2s)
+// CHECK-NEXT:   12: [B3.6].~A() (Implicit destructor)
+// CHECK-NEXT:   13: CFGScopeEnd(n1s)
+// CHECK-NEXT:   14: CFGScopeBegin(n1t)
+// CHECK-NEXT:   15: CFGScopeBegin(n2t)
+// CHECK-NEXT:    T: goto label;
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void test_goto_multiple_scopes() {
+  A a;
+  {
+    A n1s;
+    {
+      A n2s;
+      goto label;
+    }
+  }
+  {
+    int n1t;
+    {
+      int n2t;
+label:
+    }
+  }
+}
+
+// CHECK:       [B5 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B3
+// CHECK:       [B1]
+// CHECK-NEXT:    1: [B2.8].~A() (Implicit destructor)
+// CHECK-NEXT:    2: CFGScopeEnd(n2s)
+// CHECK-NEXT:    3: [B2.5].~A() (Implicit destructor)
+// CHECK-NEXT:    4: CFGScopeEnd(n1s)
+// CHECK-NEXT:    5: [B3.3].~A() (Implicit destructor)
+// CHECK-NEXT:    6: CFGScopeEnd(a)
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:   label:
+// CHECK-NEXT:    1: CFGScopeEnd(n2t)
+// CHECK-NEXT:    2: CFGScopeEnd(n1t)
+// CHECK-NEXT:    3: CFGScopeBegin(n1s)
+// CHECK-NEXT:    4:  (CXXConstructExpr, [B2.5], A)
+// CHECK-NEXT:    5: A n1s;
+// CHECK-NEXT:    6: CFGScopeBegin(n2s)
+// CHECK-NEXT:    7:  (CXXConstructExpr, [B2.8], A)
+// CHECK-NEXT:    8: A n2s;
+// CHECK-NEXT:    Preds (2): B3 B4
+// CHECK-NEXT:    Succs (1): B4
+// CHECK:       [B3]
+// CHECK-NEXT:    1: CFGScopeBegin(a)
+// CHECK-NEXT:    2:  (CXXConstructExpr, [B3.3], A)
+// CHECK-NEXT:    3: A a;
+// CHECK-NEXT:    4: CFGScopeBegin(n1t)
+// CHECK-NEXT:    5: int n1t;
+// CHECK-NEXT:    6: CFGScopeBegin(n2t)
+// CHECK-NEXT:    7: int n2t;
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    1: [B2.8].~A() (Implicit destructor)
+// CHECK-NEXT:    2: CFGScopeEnd(n2s)
+// CHECK-NEXT:    3: [B2.5].~A() (Implicit destructor)
+// CHECK-NEXT:    4: CFGScopeEnd(n1s)
+// CHECK-NEXT:    5: CFGScopeBegin(n1t)
+// CHECK-NEXT:    6: CFGScopeBegin(n2t)
+// CHECK-NEXT:    T: goto label;
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void test_backpatched_goto_multiple_scopes() {
+  A a;
+  {
+    int n1t;
+    {
+      int n2t;
+label:
+    }
+  }
+{
+  A n1s;
+  {
+    A n2s;
+    goto label;
+  }
+}
+}
+
+// CHECK:       [B8 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B7
+// CHECK:       [B1]
+// CHECK-NEXT:   label:
+// CHECK-NEXT:    1: CFGScopeEnd(n2t)
+// CHECK-NEXT:    2: CFGScopeEnd(n1t)
+// CHECK-NEXT:    Preds (4): B2 B3 B4 B6
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    T: goto label;
+// CHECK-NEXT:    Preds (1): B3
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B3]
+// CHECK-NEXT:    1: CFGScopeBegin(n2t)
+// CHECK-NEXT:    2: int n2t;
+// CHECK-NEXT:    3: UV
+// CHECK-NEXT:    4: [B3.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B3.4]
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (2): B2 B1
+// CHECK:       [B4]
+// CHECK-NEXT:    1: CFGScopeBegin(n2t)
+// CHECK-NEXT:    T: goto label;
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B5]
+// CHECK-NEXT:    1: CFGScopeBegin(n1t)
+// CHECK-NEXT:    2: int n1t;
+// CHECK-NEXT:    3: UV
+// CHECK-NEXT:    4: [B5.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B5.4]
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (2): B4 B3
+// CHECK:       [B6]
+// CHECK-NEXT:    1: CFGScopeBegin(n1t)
+// CHECK-NEXT:    2: CFGScopeBegin(n2t)
+// CHECK-NEXT:    T: goto label;
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B7]
+// CHECK-NEXT:    1: UV
+// CHECK-NEXT:    2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B7.2]
+// CHECK-NEXT:    Preds (1): B8
+// CHECK-NEXT:    Succs (2): B6 B5
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void test_multiple_goto_entering_scopes() {
+  if (UV) goto label;
+  {
+    int n1t;
+    if (UV) goto label;
+    {
+      int n2t;
+      if (UV) goto label;
+label:
+    }
+  }
+}
Index: clang/test/Analysis/nonreturn-destructors-cfg-output.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/nonreturn-destructors-cfg-output.cpp
@@ -0,0 +1,132 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -fcxx-exceptions -fexceptions -analyzer-checker=debug.DumpCFG -analyzer-config cfg-rich-constructors=true,cfg-implicit-dtors=true,cfg-lifetime=true,cfg-scopes=true %s > %t 2>&1
+// RUN: FileCheck --input-file=%t -check-prefixes=CHECK %s
+
+class A {
+public:
+  int x;
+  [[noreturn]] ~A();
+};
+
+void foo();
+extern const bool UV;
+
+// CHECK:       [B3 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B2
+//
+// CHECK:       [B1]
+// CHECK-NEXT:    1: CFGScopeEnd(a)
+// CHECK-NEXT:    2: foo
+// CHECK-NEXT:    3: [B1.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(void))
+// CHECK-NEXT:    4: [B1.3]()
+// CHECK-NEXT:    Succs (1): B0
+//
+// CHECK:       [B2 (NORETURN)]
+// CHECK-NEXT:    1: CFGScopeBegin(a)
+// CHECK-NEXT:    2:  (CXXConstructExpr, [B2.3], A)
+// CHECK-NEXT:    3: A a;
+// CHECK-NEXT:    4: [B2.3].~A() (Implicit destructor)
+// CHECK-NEXT:    5: [B2.3] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B3
+// CHECK-NEXT:    Succs (1): B0
+//
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (2): B1 B2
+void test_single_decl() {
+  {
+    A a;
+  }
+  foo();
+}
+
+// CHECK:       [B6 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B5
+//
+// CHECK:       [B1]
+// CHECK-NEXT:   label:
+// CHECK-NEXT:    1: foo
+// CHECK-NEXT:    2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(void))
+// CHECK-NEXT:    3: [B1.2]()
+// CHECK-NEXT:    Preds (4): B2 B3(Unreachable) B4 B5(Unreachable)
+// CHECK-NEXT:    Succs (1): B0
+//
+// CHECK:       [B2]
+// CHECK-NEXT:    1: CFGScopeEnd(a)
+// CHECK-NEXT:    Succs (1): B1
+//
+// CHECK:       [B3 (NORETURN)]
+// CHECK-NEXT:    1: [B5.3].~A() (Implicit destructor)
+// CHECK-NEXT:    2: [B5.3] (Lifetime ends)
+// CHECK-NEXT:    Succs (1): B0
+//
+// CHECK:       [B4]
+// CHECK-NEXT:    1: CFGScopeEnd(a)
+// CHECK-NEXT:    T: goto label;
+// CHECK-NEXT:    Succs (1): B1
+//
+// CHECK:       [B5 (NORETURN)]
+// CHECK-NEXT:    1: CFGScopeBegin(a)
+// CHECK-NEXT:    2:  (CXXConstructExpr, [B5.3], A)
+// CHECK-NEXT:    3: A a;
+// CHECK-NEXT:    4: [B5.3].~A() (Implicit destructor)
+// CHECK-NEXT:    5: [B5.3] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B6
+// CHECK-NEXT:    Succs (1): B0
+//
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (3): B1 B3 B5
+void test_forward_goto() {
+  {
+    A a;
+    goto label;
+  }
+label:
+  foo();
+}
+
+
+// The blocks B3 and B5, are inserted during backpatching goto stmt, to handle
+// scope changes.
+// CHECK:       [B6 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B3
+//
+// CHECK:       [B1]
+// CHECK-NEXT:    1: CFGScopeEnd(a)
+// CHECK-NEXT:    2: foo
+// CHECK-NEXT:    3: [B1.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(void))
+// CHECK-NEXT:    4: [B1.3]()
+// CHECK-NEXT:    Succs (1): B0
+//
+// CHECK:       [B2 (NORETURN)]
+// CHECK-NEXT:    1: [B3.3].~A() (Implicit destructor)
+// CHECK-NEXT:    2: [B3.3] (Lifetime ends)
+// CHECK-NEXT:    Succs (1): B0
+//
+// CHECK:       [B3]
+// CHECK-NEXT:   label:
+// CHECK-NEXT:    1: CFGScopeBegin(a)
+// CHECK-NEXT:    2:  (CXXConstructExpr, [B3.3], A)
+// CHECK-NEXT:    3: A a;
+// CHECK-NEXT:    Preds (3): B4 B5(Unreachable) B6
+// CHECK-NEXT:    Succs (1): B5
+//
+// CHECK:       [B4]
+// CHECK-NEXT:    1: CFGScopeEnd(a)
+// CHECK-NEXT:    T: goto label;
+// CHECK-NEXT:    Succs (1): B3
+//
+// CHECK:       [B5 (NORETURN)]
+// CHECK-NEXT:    1: [B3.3].~A() (Implicit destructor)
+// CHECK-NEXT:    2: [B3.3] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B3
+// CHECK-NEXT:    Succs (1): B0
+//
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (3): B1 B2 B5
+void test_backward_goto() {
+label:
+  {
+    A a;
+    goto label;
+  }
+  foo();
+}
Index: clang/test/Analysis/no-exit-cfg.c
===================================================================
--- clang/test/Analysis/no-exit-cfg.c
+++ clang/test/Analysis/no-exit-cfg.c
@@ -1,4 +1,5 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-config cfg-scopes=true -verify %s
 // expected-no-diagnostics
 
 // This is a test case for the issue reported in PR 2819:
Index: clang/test/Analysis/lifetime-cfg-output.cpp
===================================================================
--- clang/test/Analysis/lifetime-cfg-output.cpp
+++ clang/test/Analysis/lifetime-cfg-output.cpp
@@ -752,32 +752,40 @@
   ~B();
 };
 
-// CHECK:       [B4 (ENTRY)]
+// CHECK:       [B5 (ENTRY)]
 // CHECK-NEXT:    Succs (1): B3
 // CHECK:       [B1]
 // CHECK-NEXT:    1: i
 // CHECK-NEXT:    2: [B1.1]++
-// CHECK-NEXT:    3: [B2.2] (Lifetime ends)
-// CHECK-NEXT:    4: [B3.1] (Lifetime ends)
+// CHECK-NEXT:    3: [B2.4] (Lifetime ends)
+// CHECK-NEXT:    4: [B2.2] (Lifetime ends)
+// CHECK-NEXT:    5: [B3.1] (Lifetime ends)
 // CHECK-NEXT:    Succs (1): B0
 // CHECK:       [B2]
 // CHECK-NEXT:   label:
 // CHECK-NEXT:    1:  (CXXConstructExpr, B)
-// CHECK-NEXT:    2: B b;
-// CHECK-NEXT:    3: [B2.2] (Lifetime ends)
-// CHECK-NEXT:    T: goto label;
-// CHECK-NEXT:    Preds (2): B3 B2
-// CHECK-NEXT:    Succs (1): B2
+// CHECK-NEXT:    2: B b1;
+// CHECK-NEXT:    3:  (CXXConstructExpr, B)
+// CHECK-NEXT:    4: B b2;
+// CHECK-NEXT:    Preds (2): B3 B4
+// CHECK-NEXT:    Succs (1): B4
 // CHECK:       [B3]
 // CHECK-NEXT:    1: int i;
-// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    1: [B2.4] (Lifetime ends)
+// CHECK-NEXT:    2: [B2.2] (Lifetime ends)
+// CHECK-NEXT:    T: goto label;
+// CHECK-NEXT:    Preds (1): B2
 // CHECK-NEXT:    Succs (1): B2
 // CHECK:       [B0 (EXIT)]
 // CHECK-NEXT:    Preds (1): B1
 int backpatched_goto() {
   int i;
 label:
-  B b;
+  B b1;
+  B b2;
   goto label;
   i++;
 }
Index: clang/test/Analysis/auto-obj-dtors-cfg-output.cpp
===================================================================
--- clang/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ clang/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -442,7 +442,7 @@
   A c;
 }
 
-// CHECK:      [B8 (ENTRY)]
+// CHECK:      [B9 (ENTRY)]
 // CHECK-NEXT:   Succs (1): B7
 // CHECK:      [B1]
 // CHECK:       l1:
@@ -474,11 +474,8 @@
 // CHECK-NEXT:   Preds (1): B6
 // CHECK-NEXT:   Succs (2): B3 B2
 // CHECK:      [B5]
-// CHECK-NEXT:   1: [B6.4].~A() (Implicit destructor)
-// CHECK-NEXT:   2: [B6.2].~A() (Implicit destructor)
-// CHECK-NEXT:   T: goto l0;
 // CHECK:        Preds (1): B6
-// CHECK-NEXT:   Succs (1): B6
+// CHECK-NEXT:   Succs (1): B8
 // CHECK:      [B6]
 // CHECK:       l0:
 // WARNINGS-NEXT:   1:  (CXXConstructExpr, A)
@@ -490,13 +487,19 @@
 // CHECK-NEXT:   5: UV
 // CHECK-NEXT:   6: [B6.5] (ImplicitCastExpr, LValueToRValue, _Bool)
 // CHECK-NEXT:   T: if [B6.6]
-// CHECK-NEXT:   Preds (2): B7 B5
+// CHECK-NEXT:   Preds (2): B7 B8
 // CHECK-NEXT:   Succs (2): B5 B4
 // CHECK:      [B7]
 // WARNINGS-NEXT:   1:  (CXXConstructExpr, A)
 // ANALYZER-NEXT:   1:  (CXXConstructExpr, [B7.2], A)
 // CHECK-NEXT:   2: A a;
-// CHECK-NEXT:   Preds (1): B8
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B6
+// CHECK:      [B8]
+// CHECK-NEXT:   1: [B6.4].~A() (Implicit destructor)
+// CHECK-NEXT:   2: [B6.2].~A() (Implicit destructor)
+// CHECK-NEXT:   T: goto l0;
+// CHECK-NEXT:   Preds (1): B5
 // CHECK-NEXT:   Succs (1): B6
 // CHECK:      [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -300,6 +300,7 @@
     int distance(const_iterator L);
     const_iterator shared_parent(const_iterator L);
     bool pointsToFirstDeclaredVar() { return VarIter == 1; }
+    bool inSameLocalScope(const_iterator rhs) { return Scope == rhs.Scope; }
   };
 
 private:
@@ -349,18 +350,33 @@
 /// between this and shared_parent(L) end.
 LocalScope::const_iterator
 LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
-  llvm::SmallPtrSet<const LocalScope *, 4> ScopesOfL;
+  // one of iterators is not valid (we are not in scope), so common
+  // parent is const_iterator() (i.e. sentinel).
+  if ((*this == const_iterator()) || (L == const_iterator())) {
+    return const_iterator();
+  }
+
+  const_iterator F = *this;
+  if (F.inSameLocalScope(L)) {
+    // Iterators are in the same scope, get common subset of variables.
+    F.VarIter = std::min(F.VarIter, L.VarIter);
+    return F;
+  }
+
+  llvm::SmallDenseMap<const LocalScope *, unsigned, 4> ScopesOfL;
   while (true) {
-    ScopesOfL.insert(L.Scope);
+    ScopesOfL.try_emplace(L.Scope, L.VarIter);
     if (L == const_iterator())
       break;
     L = L.Scope->Prev;
   }
 
-  const_iterator F = *this;
   while (true) {
-    if (ScopesOfL.count(F.Scope))
+    if (auto LIt = ScopesOfL.find(F.Scope); LIt != ScopesOfL.end()) {
+      // Get common subset of variables in given scope
+      F.VarIter = std::min(F.VarIter, LIt->getSecond());
       return F;
+    }
     assert(F != const_iterator() &&
            "L iterator is not reachable from F iterator.");
     F = F.Scope->Prev;
@@ -513,9 +529,6 @@
   llvm::DenseMap<Expr *, const ConstructionContextLayer *>
       ConstructionContextMap;
 
-  using DeclsWithEndedScopeSetTy = llvm::SmallSetVector<VarDecl *, 16>;
-  DeclsWithEndedScopeSetTy DeclsWithEndedScope;
-
   bool badCFG = false;
   const CFG::BuildOptions &BuildOpts;
 
@@ -756,18 +769,20 @@
 
   CFGBlock *addInitializer(CXXCtorInitializer *I);
   void addLoopExit(const Stmt *LoopStmt);
-  void addAutomaticObjDtors(LocalScope::const_iterator B,
-                            LocalScope::const_iterator E, Stmt *S);
-  void addLifetimeEnds(LocalScope::const_iterator B,
-                       LocalScope::const_iterator E, Stmt *S);
   void addAutomaticObjHandling(LocalScope::const_iterator B,
                                LocalScope::const_iterator E, Stmt *S);
+  void addAutomaticObjDestruction(LocalScope::const_iterator B,
+                                  LocalScope::const_iterator E, Stmt *S);
+  void addScopeExitHandling(LocalScope::const_iterator B,
+                            LocalScope::const_iterator E, Stmt *S);
   void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD);
-  void addScopesEnd(LocalScope::const_iterator B, LocalScope::const_iterator E,
-                    Stmt *S);
-
-  void getDeclsWithEndedScope(LocalScope::const_iterator B,
-                              LocalScope::const_iterator E, Stmt *S);
+  void addScopeChangesHandling(LocalScope::const_iterator SrcPos,
+                               LocalScope::const_iterator DstPos,
+                               Stmt *S);
+  CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos,
+                                            CFGBlock *SrcBlk,
+                                            LocalScope::const_iterator DstPost,
+                                            CFGBlock *DstBlk);
 
   // Local scopes creation.
   LocalScope* createOrReuseLocalScope(LocalScope* Scope);
@@ -878,18 +893,6 @@
     B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext());
   }
 
-  void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
-      LocalScope::const_iterator B, LocalScope::const_iterator E);
-
-  void prependAutomaticObjLifetimeWithTerminator(CFGBlock *Blk,
-                                                 LocalScope::const_iterator B,
-                                                 LocalScope::const_iterator E);
-
-  const VarDecl *
-  prependAutomaticObjScopeEndWithTerminator(CFGBlock *Blk,
-                                            LocalScope::const_iterator B,
-                                            LocalScope::const_iterator E);
-
   void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) {
     B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable),
                     cfg->getBumpVectorContext());
@@ -907,21 +910,11 @@
       B->appendScopeBegin(VD, S, cfg->getBumpVectorContext());
   }
 
-  void prependScopeBegin(CFGBlock *B, const VarDecl *VD, const Stmt *S) {
-    if (BuildOpts.AddScopes)
-      B->prependScopeBegin(VD, S, cfg->getBumpVectorContext());
-  }
-
   void appendScopeEnd(CFGBlock *B, const VarDecl *VD, const Stmt *S) {
     if (BuildOpts.AddScopes)
       B->appendScopeEnd(VD, S, cfg->getBumpVectorContext());
   }
 
-  void prependScopeEnd(CFGBlock *B, const VarDecl *VD, const Stmt *S) {
-    if (BuildOpts.AddScopes)
-      B->prependScopeEnd(VD, S, cfg->getBumpVectorContext());
-  }
-
   /// Find a relational comparison with an expression evaluating to a
   /// boolean and a constant other than 0 and 1.
   /// e.g. if ((x < y) == 10)
@@ -1538,7 +1531,6 @@
   ConstructionContextMap.erase(E);
 }
 
-
 /// BuildCFG - Constructs a CFG from an AST (a Stmt*).  The AST can represent an
 ///  arbitrary statement.  Examples include a single expression or a function
 ///  body (compound statement).  The ownership of the returned CFG is
@@ -1556,9 +1548,6 @@
   assert(Succ == &cfg->getExit());
   Block = nullptr;  // the EXIT block is empty.  Create all other blocks lazily.
 
-  assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) &&
-         "AddImplicitDtors and AddLifetime cannot be used at the same time");
-
   if (BuildOpts.AddImplicitDtors)
     if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
       addImplicitDtorsForDestructor(DD);
@@ -1622,16 +1611,11 @@
       if (LI == LabelMap.end())
         continue;
       JumpTarget JT = LI->second;
-      prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
-                                                JT.scopePosition);
-      prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
-                                             JT.scopePosition);
-      const VarDecl *VD = prependAutomaticObjScopeEndWithTerminator(
-          B, I->scopePosition, JT.scopePosition);
-      appendScopeBegin(JT.block, VD, G);
-      addSuccessor(B, JT.block);
-    };
-    if (auto *G = dyn_cast<GCCAsmStmt>(B->getTerminator())) {
+
+      CFGBlock *SuccBlk = createScopeChangesHandlingBlock(
+          I->scopePosition, B, JT.scopePosition, JT.block);
+      addSuccessor(B, SuccBlk);
+    } else if (auto *G = dyn_cast<GCCAsmStmt>(B->getTerminator())) {
       CFGBlock *Successor  = (I+1)->block;
       for (auto *L : G->labels()) {
         LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
@@ -1798,143 +1782,197 @@
   appendLoopExit(Block, LoopStmt);
 }
 
-void CFGBuilder::getDeclsWithEndedScope(LocalScope::const_iterator B,
-                                        LocalScope::const_iterator E, Stmt *S) {
-  if (!BuildOpts.AddScopes)
+/// Adds the CFG elements for leaving the scope of automatic objects in
+/// range [B, E). This include following:
+///   * AutomaticObjectDtor for variables with non-trivial destructor
+///   * LifetimeEnds for all variables
+///   * ScopeEnd for each scope left
+void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
+                                         LocalScope::const_iterator E,
+                                         Stmt *S) {
+  if (!BuildOpts.AddScopes && !BuildOpts.AddImplicitDtors &&
+      !BuildOpts.AddLifetime)
     return;
 
   if (B == E)
     return;
 
-  // To go from B to E, one first goes up the scopes from B to P
-  // then sideways in one scope from P to P' and then down
-  // the scopes from P' to E.
-  // The lifetime of all objects between B and P end.
-  LocalScope::const_iterator P = B.shared_parent(E);
-  int Dist = B.distance(P);
-  if (Dist <= 0)
+  // Not leaving the scope, only need to handle destruction and lifetime
+  if (B.inSameLocalScope(E)) {
+    addAutomaticObjDestruction(B, E, S);
     return;
+  }
 
-  for (LocalScope::const_iterator I = B; I != P; ++I)
-    if (I.pointsToFirstDeclaredVar())
-      DeclsWithEndedScope.insert(*I);
-}
+  // Extract information about all local scopes that are left
+  SmallVector<LocalScope::const_iterator, 10> LocalScopeEndMarkers;
+  LocalScopeEndMarkers.push_back(B);
+  for (LocalScope::const_iterator I = B; I != E; ++I) {
+    if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
+      LocalScopeEndMarkers.push_back(I);
+  }
+  LocalScopeEndMarkers.push_back(E);
 
-void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
-                                         LocalScope::const_iterator E,
-                                         Stmt *S) {
-  getDeclsWithEndedScope(B, E, S);
-  if (BuildOpts.AddScopes)
-    addScopesEnd(B, E, S);
-  if (BuildOpts.AddImplicitDtors)
-    addAutomaticObjDtors(B, E, S);
-  if (BuildOpts.AddLifetime)
-    addLifetimeEnds(B, E, S);
+  // We need to leave the scope in reverse order, so we reverse the end
+  // markers
+  std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
+
+  for (std::size_t idx = 1, count = LocalScopeEndMarkers.size(); idx < count;
+       ++idx) {
+    LocalScope::const_iterator B = LocalScopeEndMarkers[idx];
+    LocalScope::const_iterator E = LocalScopeEndMarkers[idx - 1];
+    if (!B.inSameLocalScope(E))
+      addScopeExitHandling(B, E, S);
+    addAutomaticObjDestruction(B, E, S);
+  }
 }
 
-/// Add to current block automatic objects that leave the scope.
-void CFGBuilder::addLifetimeEnds(LocalScope::const_iterator B,
-                                 LocalScope::const_iterator E, Stmt *S) {
-  if (!BuildOpts.AddLifetime)
+/// Add CFG elements corresponding to call destructor and end of lifetime
+/// of all automatic variables with non-trivial destructor in range [B, E).
+/// This include AutomaticObjectDtor and LifetimeEnds elements.
+void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
+                                            LocalScope::const_iterator E,
+                                            Stmt *S) {
+  if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
     return;
 
   if (B == E)
     return;
 
-  // To go from B to E, one first goes up the scopes from B to P
-  // then sideways in one scope from P to P' and then down
-  // the scopes from P' to E.
-  // The lifetime of all objects between B and P end.
-  LocalScope::const_iterator P = B.shared_parent(E);
-  int dist = B.distance(P);
-  if (dist <= 0)
+  SmallVector<VarDecl *, 10> DeclsNonTrivial;
+  DeclsNonTrivial.reserve(B.distance(E));
+
+  for (LocalScope::const_iterator I = B; I != E; ++I)
+    if (!hasTrivialDestructor(*I))
+      DeclsNonTrivial.push_back(*I);
+
+  for (VarDecl *VD : llvm::reverse(DeclsNonTrivial)) {
+    if (BuildOpts.AddImplicitDtors) {
+      // If this destructor is marked as a no-return destructor, we need to
+      // create a new block for the destructor which does not have as a
+      // successor anything built thus far: control won't flow out of this
+      // block.
+      QualType Ty = VD->getType();
+      if (Ty->isReferenceType())
+        Ty = getReferenceInitTemporaryType(VD->getInit());
+      Ty = Context->getBaseElementType(Ty);
+
+      if (Ty->getAsCXXRecordDecl()->isAnyDestructorNoReturn())
+        Block = createNoReturnBlock();
+    }
+
+    autoCreateBlock();
+
+    // Add LifetimeEnd after automatic obj with non-trivial destructors,
+    // as they end their lifetime when the destructor returns. For trivial
+    // objects, we end lifetime with scope end.
+    if (BuildOpts.AddLifetime)
+      appendLifetimeEnds(Block, VD, S);
+    if (BuildOpts.AddImplicitDtors)
+      appendAutomaticObjDtor(Block, VD, S);
+  }
+}
+
+/// Add CFG elements corresponding to leaving a scope.
+/// Assumes that range [B, E) corresponds to single scope.
+/// This add following elements:
+///   * LifetimeEnds for all variables with non-trivial destructor
+///   * ScopeEnd for each scope left
+void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
+                                      LocalScope::const_iterator E, Stmt *S) {
+  assert(!B.inSameLocalScope(E));
+  if (!BuildOpts.AddLifetime && !BuildOpts.AddScopes)
+    return;
+
+  if (BuildOpts.AddScopes) {
+    autoCreateBlock();
+    appendScopeEnd(Block, B.getFirstVarInScope(), S);
+  }
+
+  if (!BuildOpts.AddLifetime)
     return;
 
   // We need to perform the scope leaving in reverse order
   SmallVector<VarDecl *, 10> DeclsTrivial;
-  SmallVector<VarDecl *, 10> DeclsNonTrivial;
-  DeclsTrivial.reserve(dist);
-  DeclsNonTrivial.reserve(dist);
+  DeclsTrivial.reserve(B.distance(E));
 
-  for (LocalScope::const_iterator I = B; I != P; ++I)
+  // Objects with trivial destructor ends their lifetime when their storage
+  // is destroyed, for automatic variables, this happens when the end of the
+  // scope is added.
+  for (LocalScope::const_iterator I = B; I != E; ++I)
     if (hasTrivialDestructor(*I))
       DeclsTrivial.push_back(*I);
-    else
-      DeclsNonTrivial.push_back(*I);
+
+  if (DeclsTrivial.empty())
+    return;
 
   autoCreateBlock();
-  // object with trivial destructor end their lifetime last (when storage
-  // duration ends)
   for (VarDecl *VD : llvm::reverse(DeclsTrivial))
     appendLifetimeEnds(Block, VD, S);
-
-  for (VarDecl *VD : llvm::reverse(DeclsNonTrivial))
-    appendLifetimeEnds(Block, VD, S);
 }
 
-/// Add to current block markers for ending scopes.
-void CFGBuilder::addScopesEnd(LocalScope::const_iterator B,
-                              LocalScope::const_iterator E, Stmt *S) {
-  // If implicit destructors are enabled, we'll add scope ends in
-  // addAutomaticObjDtors.
-  if (BuildOpts.AddImplicitDtors)
+/// addScopeChangesHandling - appends information about destruction, lifetime
+/// and cfgScopeEnd for variables in the scope that was left by the jump, and
+/// appends cfgScopeBegin for all scopes that where entered.
+/// We insert the cfgScopeBegin at the end of the jump node, as depending on
+/// the sourceBlock, each goto, may enter different amount of scopes.
+void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
+                                         LocalScope::const_iterator DstPos,
+                                         Stmt *S) {
+  assert(Block && "Source block should be always crated");
+  if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime &&
+      !BuildOpts.AddScopes) {
     return;
+  }
 
-  autoCreateBlock();
+  if (SrcPos == DstPos)
+    return;
+
+  // Get common scope, the jump leaves all scopes [SrcPos, BasePos), and
+  // enter all scopes between [DstPos, BasePos)
+  LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
 
-  for (VarDecl *VD : llvm::reverse(DeclsWithEndedScope))
-    appendScopeEnd(Block, VD, S);
+  // Append scope begins for scopes entered by goto
+  if (BuildOpts.AddScopes && !DstPos.inSameLocalScope(BasePos)) {
+    for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
+      if (I.pointsToFirstDeclaredVar())
+        appendScopeBegin(Block, *I, S);
+  }
+
+  // Append scopeEnds, destructor and lifetime with the terminator for
+  // block left by goto.
+  addAutomaticObjHandling(SrcPos, BasePos, S);
 }
 
-/// addAutomaticObjDtors - Add to current block automatic objects destructors
-/// for objects in range of local scope positions. Use S as trigger statement
-/// for destructors.
-void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B,
-                                      LocalScope::const_iterator E, Stmt *S) {
-  if (!BuildOpts.AddImplicitDtors)
-    return;
+/// createScopeChangesHandlingBlock - Creates a block with cfgElements
+/// corresponding to changing the scope from the source scope of the GotoStmt,
+/// to destination scope. Add destructor, lifetime and cfgScopeEnd
+/// CFGElements to newly created CFGBlock, that will have the CFG terminator
+/// transferred.
+CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
+    LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk,
+    LocalScope::const_iterator DstPos, CFGBlock *DstBlk) {
+  if (SrcPos == DstPos)
+    return DstBlk;
 
-  if (B == E)
-    return;
+  if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime &&
+      (!BuildOpts.AddScopes || SrcPos.inSameLocalScope(DstPos)))
+    return DstBlk;
 
-  // We need to append the destructors in reverse order, but any one of them
-  // may be a no-return destructor which changes the CFG. As a result, buffer
-  // this sequence up and replay them in reverse order when appending onto the
-  // CFGBlock(s).
-  SmallVector<VarDecl*, 10> Decls;
-  Decls.reserve(B.distance(E));
-  for (LocalScope::const_iterator I = B; I != E; ++I)
-    Decls.push_back(*I);
+  // We will update CFBBuilder when creating new block, restore the
+  // previous state at exit.
+  SaveAndRestore save_Block(Block), save_Succ(Succ);
 
-  for (VarDecl *VD : llvm::reverse(Decls)) {
-    if (hasTrivialDestructor(VD)) {
-      // If AddScopes is enabled and *I is a first variable in a scope, add a
-      // ScopeEnd marker in a Block.
-      if (BuildOpts.AddScopes && DeclsWithEndedScope.count(VD)) {
-        autoCreateBlock();
-        appendScopeEnd(Block, VD, S);
-      }
-      continue;
-    }
-    // If this destructor is marked as a no-return destructor, we need to
-    // create a new block for the destructor which does not have as a successor
-    // anything built thus far: control won't flow out of this block.
-    QualType Ty = VD->getType();
-    if (Ty->isReferenceType()) {
-      Ty = getReferenceInitTemporaryType(VD->getInit());
-    }
-    Ty = Context->getBaseElementType(Ty);
+  // Create a new block, and transfer terminator
+  Block = createBlock(false);
+  Block->setTerminator(SrcBlk->getTerminator());
+  SrcBlk->setTerminator(CFGTerminator());
+  addSuccessor(Block, DstBlk);
 
-    if (Ty->getAsCXXRecordDecl()->isAnyDestructorNoReturn())
-      Block = createNoReturnBlock();
-    else
-      autoCreateBlock();
+  // Fill the created Block with the required elements.
+  addScopeChangesHandling(SrcPos, DstPos, Block->getTerminatorStmt());
 
-    // Add ScopeEnd just after automatic obj destructor.
-    if (BuildOpts.AddScopes && DeclsWithEndedScope.count(VD))
-      appendScopeEnd(Block, VD, S);
-    appendAutomaticObjDtor(Block, VD, S);
-  }
+  assert(Block && "There should be at least one scope changing Block");
+  return Block;
 }
 
 /// addImplicitDtorsForDestructor - Add implicit destructors generated for
@@ -2079,8 +2117,6 @@
 /// const reference. Will reuse Scope if not NULL.
 LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
                                                 LocalScope* Scope) {
-  assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) &&
-         "AddImplicitDtors and AddLifetime cannot be used at the same time");
   if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime &&
       !BuildOpts.AddScopes)
     return Scope;
@@ -2089,17 +2125,12 @@
   if (!VD->hasLocalStorage())
     return Scope;
 
-  if (BuildOpts.AddImplicitDtors) {
-    if (!hasTrivialDestructor(VD) || BuildOpts.AddScopes) {
-      // Add the variable to scope
-      Scope = createOrReuseLocalScope(Scope);
-      Scope->addVar(VD);
-      ScopePos = Scope->begin();
-    }
+  if (!BuildOpts.AddLifetime && !BuildOpts.AddScopes &&
+      hasTrivialDestructor(VD)) {
+    assert(BuildOpts.AddImplicitDtors);
     return Scope;
   }
 
-  assert(BuildOpts.AddLifetime);
   // Add the variable to scope
   Scope = createOrReuseLocalScope(Scope);
   Scope->addVar(VD);
@@ -2115,63 +2146,6 @@
   addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
 }
 
-/// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for
-/// variables with automatic storage duration to CFGBlock's elements vector.
-/// Elements will be prepended to physical beginning of the vector which
-/// happens to be logical end. Use blocks terminator as statement that specifies
-/// destructors call site.
-/// FIXME: This mechanism for adding automatic destructors doesn't handle
-/// no-return destructors properly.
-void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
-    LocalScope::const_iterator B, LocalScope::const_iterator E) {
-  if (!BuildOpts.AddImplicitDtors)
-    return;
-  BumpVectorContext &C = cfg->getBumpVectorContext();
-  CFGBlock::iterator InsertPos
-    = Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C);
-  for (LocalScope::const_iterator I = B; I != E; ++I)
-    InsertPos = Blk->insertAutomaticObjDtor(InsertPos, *I,
-                                            Blk->getTerminatorStmt());
-}
-
-/// prependAutomaticObjLifetimeWithTerminator - Prepend lifetime CFGElements for
-/// variables with automatic storage duration to CFGBlock's elements vector.
-/// Elements will be prepended to physical beginning of the vector which
-/// happens to be logical end. Use blocks terminator as statement that specifies
-/// where lifetime ends.
-void CFGBuilder::prependAutomaticObjLifetimeWithTerminator(
-    CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) {
-  if (!BuildOpts.AddLifetime)
-    return;
-  BumpVectorContext &C = cfg->getBumpVectorContext();
-  CFGBlock::iterator InsertPos =
-      Blk->beginLifetimeEndsInsert(Blk->end(), B.distance(E), C);
-  for (LocalScope::const_iterator I = B; I != E; ++I) {
-    InsertPos =
-        Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminatorStmt());
-  }
-}
-
-/// prependAutomaticObjScopeEndWithTerminator - Prepend scope end CFGElements for
-/// variables with automatic storage duration to CFGBlock's elements vector.
-/// Elements will be prepended to physical beginning of the vector which
-/// happens to be logical end. Use blocks terminator as statement that specifies
-/// where scope ends.
-const VarDecl *
-CFGBuilder::prependAutomaticObjScopeEndWithTerminator(
-    CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) {
-  if (!BuildOpts.AddScopes)
-    return nullptr;
-  BumpVectorContext &C = cfg->getBumpVectorContext();
-  CFGBlock::iterator InsertPos =
-      Blk->beginScopeEndInsert(Blk->end(), 1, C);
-  LocalScope::const_iterator PlaceToInsert = B;
-  for (LocalScope::const_iterator I = B; I != E; ++I)
-    PlaceToInsert = I;
-  Blk->insertScopeEnd(InsertPos, *PlaceToInsert, Blk->getTerminatorStmt());
-  return *PlaceToInsert;
-}
-
 /// Visit - Walk the subtree of a statement and add extra
 ///   blocks for ternary operators, &&, and ||.  We also process "," and
 ///   DeclStmts (which may contain nested control-flow).
@@ -3457,8 +3431,8 @@
     BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
   else {
     JumpTarget JT = I->second;
-    addAutomaticObjHandling(ScopePos, JT.scopePosition, G);
     addSuccessor(Block, JT.block);
+    addScopeChangesHandling(ScopePos, JT.scopePosition, G);
   }
 
   return Block;
Index: clang/include/clang/Analysis/CFG.h
===================================================================
--- clang/include/clang/Analysis/CFG.h
+++ clang/include/clang/Analysis/CFG.h
@@ -1122,19 +1122,10 @@
     Elements.push_back(CFGScopeBegin(VD, S), C);
   }
 
-  void prependScopeBegin(const VarDecl *VD, const Stmt *S,
-                         BumpVectorContext &C) {
-    Elements.insert(Elements.rbegin(), 1, CFGScopeBegin(VD, S), C);
-  }
-
   void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
     Elements.push_back(CFGScopeEnd(VD, S), C);
   }
 
-  void prependScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
-    Elements.insert(Elements.rbegin(), 1, CFGScopeEnd(VD, S), C);
-  }
-
   void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
     Elements.push_back(CFGBaseDtor(BS), C);
   }
@@ -1162,44 +1153,6 @@
   void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
     Elements.push_back(CFGDeleteDtor(RD, DE), C);
   }
-
-  // Destructors must be inserted in reversed order. So insertion is in two
-  // steps. First we prepare space for some number of elements, then we insert
-  // the elements beginning at the last position in prepared space.
-  iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
-      BumpVectorContext &C) {
-    return iterator(Elements.insert(I.base(), Cnt,
-                                    CFGAutomaticObjDtor(nullptr, nullptr), C));
-  }
-  iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
-    *I = CFGAutomaticObjDtor(VD, S);
-    return ++I;
-  }
-
-  // Scope leaving must be performed in reversed order. So insertion is in two
-  // steps. First we prepare space for some number of elements, then we insert
-  // the elements beginning at the last position in prepared space.
-  iterator beginLifetimeEndsInsert(iterator I, size_t Cnt,
-                                   BumpVectorContext &C) {
-    return iterator(
-        Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C));
-  }
-  iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) {
-    *I = CFGLifetimeEnds(VD, S);
-    return ++I;
-  }
-
-  // Scope leaving must be performed in reversed order. So insertion is in two
-  // steps. First we prepare space for some number of elements, then we insert
-  // the elements beginning at the last position in prepared space.
-  iterator beginScopeEndInsert(iterator I, size_t Cnt, BumpVectorContext &C) {
-    return iterator(
-        Elements.insert(I.base(), Cnt, CFGScopeEnd(nullptr, nullptr), C));
-  }
-  iterator insertScopeEnd(iterator I, VarDecl *VD, Stmt *S) {
-    *I = CFGScopeEnd(VD, S);
-    return ++I;
-  }
 };
 
 /// CFGCallback defines methods that should be called when a logical
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to