mgehre updated this revision to Diff 53261.
mgehre added a comment.

Remove unused CFGBuilder::prependLifetimeEndsWithTerminator


http://reviews.llvm.org/D15031

Files:
  include/clang/Analysis/AnalysisContext.h
  include/clang/Analysis/CFG.h
  include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
  lib/Analysis/AnalysisDeclContext.cpp
  lib/Analysis/CFG.cpp
  lib/StaticAnalyzer/Core/AnalysisManager.cpp
  lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  test/Analysis/analyzer-config.c
  test/Analysis/analyzer-config.cpp
  test/Analysis/lifetime-cfg-output.cpp

Index: test/Analysis/lifetime-cfg-output.cpp
===================================================================
--- /dev/null
+++ test/Analysis/lifetime-cfg-output.cpp
@@ -0,0 +1,735 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-lifetime=true -analyzer-config cfg-implicit-dtors=false %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+extern bool UV;
+class A {
+public:
+// CHECK:       [B2 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B1]
+// CHECK-NEXT:    1: true
+// CHECK-NEXT:    2: UV
+// CHECK-NEXT:    3: [B1.2] = [B1.1]
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+    A() { 
+        UV = true;
+    }
+// CHECK:       [B3 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B1]
+// CHECK-NEXT:    1: 0
+// CHECK-NEXT:    2: this
+// CHECK-NEXT:    3: [B1.2]->p
+// CHECK-NEXT:    4: [B1.3] (ImplicitCastExpr, LValueToRValue, int *)
+// CHECK-NEXT:    5: *[B1.4]
+// CHECK-NEXT:    6: [B1.5] = [B1.1]
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1: this
+// CHECK-NEXT:    2: [B2.1]->p
+// CHECK-NEXT:    3: [B2.2] (ImplicitCastExpr, LValueToRValue, int *)
+// CHECK-NEXT:    4: [B2.3] (ImplicitCastExpr, PointerToBoolean, _Bool)
+// CHECK-NEXT:    T: if [B2.4]
+// CHECK-NEXT:    Preds (1): B3
+// CHECK-NEXT:    Succs (2): B1 B0
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (2): B1 B2
+    ~A() {
+        if(p)
+            *p = 0;
+    }
+// CHECK:       [B2 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B1]
+// CHECK-NEXT:    1: 1
+// CHECK-NEXT:    2: return [B1.1];
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+    operator int() const { return 1; }
+    int* p;
+};
+
+// CHECK:       [B2 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B1]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    3: a
+// CHECK-NEXT:    4: [B1.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    5: const A &b = a;
+// CHECK-NEXT:    6: A() (CXXConstructExpr, class A)
+// CHECK-NEXT:    7: [B1.6] (BindTemporary)
+// CHECK-NEXT:    8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    9: [B1.8]
+// CHECK-NEXT:   10: const A &c = A();
+// CHECK-NEXT:   11: [B1.10] (Lifetime ends)
+// CHECK-NEXT:   12: [B1.2] (Lifetime ends)
+// CHECK-NEXT:   13: [B1.5] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void test_const_ref() {
+  A a;
+  const A& b = a;
+  const A& c = A();
+}
+
+// CHECK:      [B2 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B1
+// CHECK:       [B1]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A [2])
+// CHECK-NEXT:    2: A a[2];
+// CHECK-NEXT:    3:  (CXXConstructExpr, class A [0])
+// CHECK-NEXT:    4: A b[0];
+// lifetime of a ends when its destructors are run
+// CHECK-NEXT:    5: [B1.2] (Lifetime ends)
+// lifetime of b ends when its storage duration ends
+// CHECK-NEXT:    6: [B1.4] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:      [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void test_array() {
+  A a[2];
+  A b[0];
+}
+
+// CHECK:      [B2 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B1
+// CHECK:       [B1]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    3:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    4: A c;
+// CHECK-NEXT:    5:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    6: A d;
+// CHECK-NEXT:    7: [B1.6] (Lifetime ends)
+// CHECK-NEXT:    8: [B1.4] (Lifetime ends)
+// CHECK-NEXT:    9:  (CXXConstructExpr, class A)
+// CHECK-NEXT:   10: A b;
+// CHECK-NEXT:   11: [B1.10] (Lifetime ends)
+// CHECK-NEXT:   12: [B1.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:      [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void test_scope() {
+  A a;
+  { A c;
+    A d;
+  }
+  A b;
+}
+
+// CHECK:      [B4 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B3
+// CHECK:       [B1]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: [B1.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B3.4] (Lifetime ends)
+// CHECK-NEXT:    5: [B3.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B3
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1: return;
+// CHECK-NEXT:    2: [B3.4] (Lifetime ends)
+// CHECK-NEXT:    3: [B3.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B3
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B3]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    3:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    4: A b;
+// CHECK-NEXT:    5: UV
+// CHECK-NEXT:    6: [B3.5] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B3.6]
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (2): B2 B1
+
+// CHECK:      [B0 (EXIT)]
+// CHECK-NEXT:   Preds (2): B1 B2
+void test_return() {
+  A a;
+  A b;
+  if (UV) return;
+  A c;
+}
+
+// CHECK:       [B5 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B4
+// CHECK:       [B1]
+// CHECK-NEXT:    1: [B4.6] (Lifetime ends)
+// CHECK-NEXT:    2: [B4.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (2): B2 B3
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: [B2.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B3]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: [B3.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B4]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    3: a
+// CHECK-NEXT:    4: [B4.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    5: [B4.4] (CXXConstructExpr, class A)
+// CHECK-NEXT:    6: A b = a;
+// CHECK-NEXT:    7: b
+// CHECK-NEXT:    8: [B4.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    9: [B4.8].operator int
+// CHECK-NEXT:   10: [B4.8]
+// CHECK-NEXT:   11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT:   12: [B4.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:    T: if [B4.12]
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (2): B3 B2
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void test_if_implicit_scope() {
+  A a;
+  if (A b = a)
+    A c;
+  else A c;
+}
+
+// CHECK:       [B9 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B8
+// CHECK:       [B1]
+// CHECK-NEXT:    1: [B8.6] (Lifetime ends)
+// CHECK-NEXT:    2:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    3: A e;
+// CHECK-NEXT:    4: [B1.3] (Lifetime ends)
+// CHECK-NEXT:    5: [B8.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (2): B2 B5
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A d;
+// CHECK-NEXT:    3: [B2.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B4.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B3]
+// CHECK-NEXT:    1: return;
+// CHECK-NEXT:    2: [B4.2] (Lifetime ends)
+// CHECK-NEXT:    3: [B8.6] (Lifetime ends)
+// CHECK-NEXT:    4: [B8.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B4]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: UV
+// CHECK-NEXT:    4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B4.4]
+// CHECK-NEXT:    Preds (1): B8
+// CHECK-NEXT:    Succs (2): B3 B2
+// CHECK:       [B5]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A d;
+// CHECK-NEXT:    3: [B5.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B7.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B6]
+// CHECK-NEXT:    1: return;
+// CHECK-NEXT:    2: [B7.2] (Lifetime ends)
+// CHECK-NEXT:    3: [B8.6] (Lifetime ends)
+// CHECK-NEXT:    4: [B8.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B7]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: UV
+// CHECK-NEXT:    4: [B7.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B7.4]
+// CHECK-NEXT:    Preds (1): B8
+// CHECK-NEXT:    Succs (2): B6 B5
+// CHECK:       [B8]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    3: a
+// CHECK-NEXT:    4: [B8.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    5: [B8.4] (CXXConstructExpr, class A)
+// CHECK-NEXT:    6: A b = a;
+// CHECK-NEXT:    7: b
+// CHECK-NEXT:    8: [B8.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    9: [B8.8].operator int
+// CHECK-NEXT:   10: [B8.8]
+// CHECK-NEXT:   11: [B8.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT:   12: [B8.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:    T: if [B8.12]
+// CHECK-NEXT:    Preds (1): B9
+// CHECK-NEXT:    Succs (2): B7 B4
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (3): B1 B3 B6
+void test_if_jumps() {
+  A a;
+  if (A b = a) {
+    A c;
+    if (UV) return;
+    A d;
+  } else {
+    A c;
+    if (UV) return;
+    A d;
+  }
+  A e;
+}
+
+// CHECK:       [B6 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B5
+// CHECK:       [B1]
+// CHECK-NEXT:    1: [B4.4] (Lifetime ends)
+// CHECK-NEXT:    2: [B5.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    Preds (1): B3
+// CHECK-NEXT:    Succs (1): B4
+// CHECK:       [B3]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: [B3.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B4.4] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    1: a
+// CHECK-NEXT:    2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    3: [B4.2] (CXXConstructExpr, class A)
+// CHECK-NEXT:    4: A b = a;
+// CHECK-NEXT:    5: b
+// CHECK-NEXT:    6: [B4.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    7: [B4.6].operator int
+// CHECK-NEXT:    8: [B4.6]
+// CHECK-NEXT:    9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT:   10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:    T: while [B4.10]
+// CHECK-NEXT:    Preds (2): B2 B5
+// CHECK-NEXT:    Succs (2): B3 B1
+// CHECK:       [B5]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    Preds (1): B6
+// CHECK-NEXT:    Succs (1): B4
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void test_while_implicit_scope() {
+  A a;
+  while (A b = a)
+    A c;
+}
+
+// CHECK:       [B12 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B11
+// CHECK:       [B1]
+// CHECK-NEXT:    1: [B10.4] (Lifetime ends)
+// CHECK-NEXT:    2:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    3: A e;
+// CHECK-NEXT:    4: [B1.3] (Lifetime ends)
+// CHECK-NEXT:    5: [B11.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (2): B8 B10
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    Preds (2): B3 B6
+// CHECK-NEXT:    Succs (1): B10
+// CHECK:       [B3]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A d;
+// CHECK-NEXT:    3: [B3.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    5: [B10.4] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    1: return;
+// CHECK-NEXT:    2: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    3: [B10.4] (Lifetime ends)
+// CHECK-NEXT:    4: [B11.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B5]
+// CHECK-NEXT:    1: UV
+// CHECK-NEXT:    2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B5.2]
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (2): B4 B3
+// CHECK:       [B6]
+// CHECK-NEXT:    1: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    2: [B10.4] (Lifetime ends)
+// CHECK-NEXT:    T: continue;
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B7]
+// CHECK-NEXT:    1: UV
+// CHECK-NEXT:    2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B7.2]
+// CHECK-NEXT:    Preds (1): B9
+// CHECK-NEXT:    Succs (2): B6 B5
+// CHECK:       [B8]
+// CHECK-NEXT:    1: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    T: break;
+// CHECK-NEXT:    Preds (1): B9
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B9]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: UV
+// CHECK-NEXT:    4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B9.4]
+// CHECK-NEXT:    Preds (1): B10
+// CHECK-NEXT:    Succs (2): B8 B7
+// CHECK:       [B10]
+// CHECK-NEXT:    1: a
+// CHECK-NEXT:    2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    3: [B10.2] (CXXConstructExpr, class A)
+// CHECK-NEXT:    4: A b = a;
+// CHECK-NEXT:    5: b
+// CHECK-NEXT:    6: [B10.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    7: [B10.6].operator int
+// CHECK-NEXT:    8: [B10.6]
+// CHECK-NEXT:    9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT:   10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:    T: while [B10.10]
+// CHECK-NEXT:    Preds (2): B2 B11
+// CHECK-NEXT:    Succs (2): B9 B1
+// CHECK:       [B11]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    Preds (1): B12
+// CHECK-NEXT:    Succs (1): B10
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (2): B1 B4
+void test_while_jumps() {
+  A a;
+  while (A b = a) {
+    A c;
+    if (UV) break;
+    if (UV) continue;
+    if (UV) return;
+    A d;
+  }
+  A e;
+}
+
+// CHECK:       [B12 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B11
+// CHECK:       [B1]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A d;
+// CHECK-NEXT:    3: [B1.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B11.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (2): B8 B2
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1: UV
+// CHECK-NEXT:    2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: do ... while [B2.2]
+// CHECK-NEXT:    Preds (2): B3 B6
+// CHECK-NEXT:    Succs (2): B10 B1
+// CHECK:       [B3]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: [B3.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    1: return;
+// CHECK-NEXT:    2: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    3: [B11.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B5]
+// CHECK-NEXT:    1: UV
+// CHECK-NEXT:    2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B5.2]
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (2): B4 B3
+// CHECK:       [B6]
+// CHECK-NEXT:    1: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    T: continue;
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B7]
+// CHECK-NEXT:    1: UV
+// CHECK-NEXT:    2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B7.2]
+// CHECK-NEXT:    Preds (1): B9
+// CHECK-NEXT:    Succs (2): B6 B5
+// CHECK:       [B8]
+// CHECK-NEXT:    1: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    T: break;
+// CHECK-NEXT:    Preds (1): B9
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B9]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A b;
+// CHECK-NEXT:    3: UV
+// CHECK-NEXT:    4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B9.4]
+// CHECK-NEXT:    Preds (2): B10 B11
+// CHECK-NEXT:    Succs (2): B8 B7
+// CHECK:       [B10]
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B9
+// CHECK:       [B11]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    Preds (1): B12
+// CHECK-NEXT:    Succs (1): B9
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (2): B1 B4
+void test_do_jumps() {
+  A a;
+  do {
+    A b;
+    if (UV) break;
+    if (UV) continue;
+    if (UV) return;
+    A c;
+  } while (UV);
+  A d;
+}
+
+// CHECK:       [B6 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B5
+// CHECK:       [B1]
+// CHECK-NEXT:    1: [B4.4] (Lifetime ends)
+// CHECK-NEXT:    2: [B5.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    Preds (1): B3
+// CHECK-NEXT:    Succs (1): B4
+// CHECK:       [B3]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A c;
+// CHECK-NEXT:    3: [B3.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B4.4] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    1: a
+// CHECK-NEXT:    2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    3: [B4.2] (CXXConstructExpr, class A)
+// CHECK-NEXT:    4: A b = a;
+// CHECK-NEXT:    5: b
+// CHECK-NEXT:    6: [B4.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    7: [B4.6].operator int
+// CHECK-NEXT:    8: [B4.6]
+// CHECK-NEXT:    9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT:   10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:    T: for (...; [B4.10]; )
+// CHECK-NEXT:    Preds (2): B2 B5
+// CHECK-NEXT:    Succs (2): B3 B1
+// CHECK:       [B5]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    Preds (1): B6
+// CHECK-NEXT:    Succs (1): B4
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void test_for_implicit_scope() {
+  for (A a; A b = a; )
+    A c;
+}
+
+// CHECK:       [B12 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B11
+// CHECK:       [B1]
+// CHECK-NEXT:    1: [B10.4] (Lifetime ends)
+// CHECK-NEXT:    2: [B11.4] (Lifetime ends)
+// CHECK-NEXT:    3:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    4: A f;
+// CHECK-NEXT:    5: [B1.4] (Lifetime ends)
+// CHECK-NEXT:    6: [B11.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (2): B8 B10
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    Preds (2): B3 B6
+// CHECK-NEXT:    Succs (1): B10
+// CHECK:       [B3]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A e;
+// CHECK-NEXT:    3: [B3.2] (Lifetime ends)
+// CHECK-NEXT:    4: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    5: [B10.4] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    1: return;
+// CHECK-NEXT:    2: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    3: [B10.4] (Lifetime ends)
+// CHECK-NEXT:    4: [B11.4] (Lifetime ends)
+// CHECK-NEXT:    5: [B11.2] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B5
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B5]
+// CHECK-NEXT:    1: UV
+// CHECK-NEXT:    2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B5.2]
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (2): B4 B3
+// CHECK:       [B6]
+// CHECK-NEXT:    1: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    T: continue;
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B7]
+// CHECK-NEXT:    1: UV
+// CHECK-NEXT:    2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B7.2]
+// CHECK-NEXT:    Preds (1): B9
+// CHECK-NEXT:    Succs (2): B6 B5
+// CHECK:       [B8]
+// CHECK-NEXT:    1: [B9.2] (Lifetime ends)
+// CHECK-NEXT:    T: break;
+// CHECK-NEXT:    Preds (1): B9
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B9]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A d;
+// CHECK-NEXT:    3: UV
+// CHECK-NEXT:    4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT:    T: if [B9.4]
+// CHECK-NEXT:    Preds (1): B10
+// CHECK-NEXT:    Succs (2): B8 B7
+// CHECK:       [B10]
+// CHECK-NEXT:    1: b
+// CHECK-NEXT:    2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    3: [B10.2] (CXXConstructExpr, class A)
+// CHECK-NEXT:    4: A c = b;
+// CHECK-NEXT:    5: c
+// CHECK-NEXT:    6: [B10.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT:    7: [B10.6].operator int
+// CHECK-NEXT:    8: [B10.6]
+// CHECK-NEXT:    9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT:   10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:    T: for (...; [B10.10]; )
+// CHECK-NEXT:    Preds (2): B2 B11
+// CHECK-NEXT:    Succs (2): B9 B1
+// CHECK:       [B11]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    3:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    4: A b;
+// CHECK-NEXT:    Preds (1): B12
+// CHECK-NEXT:    Succs (1): B10
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (2): B1 B4
+void test_for_jumps() {
+  A a;
+  for (A b; A c = b; ) {
+    A d;
+    if (UV) break;
+    if (UV) continue;
+    if (UV) return;
+    A e;
+  }
+  A f;
+}
+
+// CHECK:       [B2 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B1]
+// CHECK-NEXT:    1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:    2: A a;
+// CHECK-NEXT:    3: int n;
+// CHECK-NEXT:    4: n
+// CHECK-NEXT:    5: &[B1.4]
+// CHECK-NEXT:    6: a
+// CHECK-NEXT:    7: [B1.6].p
+// CHECK-NEXT:    8: [B1.7] = [B1.5]
+// CHECK-NEXT:    9: [B1.2] (Lifetime ends)
+// CHECK-NEXT:   10: [B1.3] (Lifetime ends)
+// CHECK-NEXT:    Preds (1): B2
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void test_trivial_vs_non_trivial_order() {
+  A a;
+  int n;
+  a.p = &n;
+}
+
+// CHECK:       [B4 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B3
+// CHECK:       [B1]
+// CHECK-NEXT:   a:
+// CHECK-NEXT:    1: 1
+// CHECK-NEXT:    2: i
+// CHECK-NEXT:    3: [B1.2] = [B1.1]
+// CHECK-NEXT:    4: [B2.1] (Lifetime ends)
+// CHECK-NEXT:    Preds (2): B2 B3
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1: int i;
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B3]
+// CHECK-NEXT:    T: goto a;
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void goto_past_declaration() {
+  goto a;
+  int i;
+  a:
+  i = 1;
+}
+
+// CHECK:       [B4 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B3
+// CHECK:       [B1]
+// CHECK-NEXT:   a:
+// CHECK-NEXT:    1: 1
+// CHECK-NEXT:    2: k
+// CHECK-NEXT:    3: [B1.2] = [B1.1]
+// CHECK-NEXT:    4: [B2.4] (Lifetime ends)
+// CHECK-NEXT:    Preds (2): B2 B3
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1: int j;
+// CHECK-NEXT:    2: [B2.1] (Lifetime ends)
+// CHECK-NEXT:    3: [B3.1] (Lifetime ends)
+// CHECK-NEXT:    4: int k;
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B3]
+// CHECK-NEXT:    1: int i;
+// CHECK-NEXT:    2: [B3.1] (Lifetime ends)
+// CHECK-NEXT:    T: goto a;
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+void goto_past_declaration2() {
+  {
+    int i;
+    goto a;
+    int j;
+  }
+  {
+    int k;
+    a:
+    k = 1;
+  }
+}
\ No newline at end of file
Index: test/Analysis/analyzer-config.cpp
===================================================================
--- test/Analysis/analyzer-config.cpp
+++ test/Analysis/analyzer-config.cpp
@@ -23,6 +23,8 @@
 // CHECK-NEXT: c++-stdlib-inlining = true
 // CHECK-NEXT: c++-template-inlining = true
 // CHECK-NEXT: cfg-conditional-static-initializers = true
+// CHECK-NEXT: cfg-implicit-dtors = true
+// CHECK-NEXT: cfg-lifetime = false
 // CHECK-NEXT: cfg-temporary-dtors = false
 // CHECK-NEXT: faux-bodies = true
 // CHECK-NEXT: graph-trim-interval = 1000
@@ -38,4 +40,4 @@
 // CHECK-NEXT: region-store-small-struct-limit = 2
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 20
+// CHECK-NEXT: num-entries = 22
Index: test/Analysis/analyzer-config.c
===================================================================
--- test/Analysis/analyzer-config.c
+++ test/Analysis/analyzer-config.c
@@ -12,6 +12,8 @@
 
 // CHECK: [config]
 // CHECK-NEXT: cfg-conditional-static-initializers = true
+// CHECK-NEXT: cfg-implicit-dtors = true
+// CHECK-NEXT: cfg-lifetime = false
 // CHECK-NEXT: cfg-temporary-dtors = false
 // CHECK-NEXT: faux-bodies = true
 // CHECK-NEXT: graph-trim-interval = 1000
@@ -27,5 +29,5 @@
 // CHECK-NEXT: region-store-small-struct-limit = 2
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 15
+// CHECK-NEXT: num-entries = 17
 
Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp
===================================================================
--- lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -570,6 +570,7 @@
   }
   case CFGElement::TemporaryDtor:
   case CFGElement::NewAllocator:
+  case CFGElement::LifetimeEnds:
     llvm_unreachable("not yet implemented!");
   }
 
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -310,6 +310,8 @@
     case CFGElement::TemporaryDtor:
       ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
       return;
+    case CFGElement::LifetimeEnds:
+      return;
   }
 }
 
Index: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
===================================================================
--- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -153,6 +153,18 @@
                           /* Default = */ false);
 }
 
+bool AnalyzerOptions::includeImplicitDtorsInCFG() {
+  return getBooleanOption(IncludeImplicitDtorsInCFG,
+                          "cfg-implicit-dtors",
+                          /* Default = */ true);
+}
+
+bool AnalyzerOptions::includeLifetimeInCFG() {
+  return getBooleanOption(IncludeLifetimeInCFG,
+                          "cfg-lifetime",
+                          /* Default = */ false);
+}
+
 bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
   return getBooleanOption(InlineCXXStandardLibrary,
                           "c++-stdlib-inlining",
Index: lib/StaticAnalyzer/Core/AnalysisManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -23,9 +23,10 @@
                                  AnalyzerOptions &Options,
                                  CodeInjector *injector)
   : AnaCtxMgr(Options.UnoptimizedCFG,
-              /*AddImplicitDtors=*/true,
+              Options.includeImplicitDtorsInCFG(),
               /*AddInitializers=*/true,
               Options.includeTemporaryDtorsInCFG(),
+	      Options.includeLifetimeInCFG(),
               Options.shouldSynthesizeBodies(),
               Options.shouldConditionalizeStaticInitializers(),
               /*addCXXNewAllocator=*/true,
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -233,6 +233,7 @@
     }
 
     int distance(const_iterator L);
+    const_iterator shared_parent(const_iterator L);
   };
 
   friend class const_iterator;
@@ -275,6 +276,27 @@
   return D;
 }
 
+/// Calculates the closest parent of this iterator
+/// that is in a scope reachable through the parents of L.
+/// I.e. when using 'goto' from this to L, the lifetime of all variables
+/// between this and shared_parent(L) end.
+LocalScope::const_iterator LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
+  const_iterator F = *this;
+  while(true) {
+    const_iterator LL = L;
+    while (true) {
+      if(F.Scope == LL.Scope)
+        return F;
+      if (LL == const_iterator())
+        break;
+      LL = LL.Scope->Prev;
+    }
+    assert (F != const_iterator()
+        && "L iterator is not reachable from F iterator.");
+    F = F.Scope->Prev;
+  }
+}
+
 /// Structure for specifying position in CFG during its build process. It
 /// consists of CFGBlock that specifies position in CFG and
 /// LocalScope::const_iterator that specifies position in LocalScope graph.
@@ -579,6 +601,10 @@
   CFGBlock *addInitializer(CXXCtorInitializer *I);
   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 addImplicitDtorsForDestructor(const CXXDestructorDecl *DD);
 
   // Local scopes creation.
@@ -619,6 +645,10 @@
     B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
   }
 
+  void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) {
+    B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext());
+  }
+
   void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
     B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext());
   }
@@ -957,7 +987,8 @@
 
     return TryResult();
   }
-  
+
+  bool hasTrivialDestructor(VarDecl *VD);
 };
 
 inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
@@ -1031,6 +1062,8 @@
   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);
@@ -1206,7 +1239,58 @@
 
   return Init->getType();
 }
-  
+
+void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
+                                         LocalScope::const_iterator E, Stmt *S) {
+  if (BuildOpts.AddImplicitDtors)
+    addAutomaticObjDtors(B, E, S);
+  if (BuildOpts.AddLifetime)
+    addLifetimeEnds(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)
+    return;
+
+  if (B == E)
+    return;
+
+  // To 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)
+    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);
+
+  for (LocalScope::const_iterator I = B; I != P; ++I)
+    if(hasTrivialDestructor(*I))
+        DeclsTrivial.push_back(*I);
+    else
+        DeclsNonTrivial.push_back(*I);
+
+  autoCreateBlock();
+  // object with trivial destructor end their lifetime last (when storage duration ends)
+  for (SmallVectorImpl<VarDecl*>::reverse_iterator I = DeclsTrivial.rbegin(),
+                                                   E = DeclsTrivial.rend();
+       I != E; ++I)
+    appendLifetimeEnds(Block, *I, S);
+
+  for (SmallVectorImpl<VarDecl*>::reverse_iterator I = DeclsNonTrivial.rbegin(),
+                                                   E = DeclsNonTrivial.rend();
+       I != E; ++I)
+    appendLifetimeEnds(Block, *I, S);
+}
+
 /// addAutomaticObjDtors - Add to current block automatic objects destructors
 /// for objects in range of local scope positions. Use S as trigger statement
 /// for destructors.
@@ -1306,7 +1390,7 @@
 /// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement
 /// that should create implicit scope (e.g. if/else substatements). 
 void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
-  if (!BuildOpts.AddImplicitDtors)
+  if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
     return;
 
   LocalScope *Scope = nullptr;
@@ -1331,21 +1415,59 @@
 /// reuse Scope if not NULL.
 LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
                                                  LocalScope* Scope) {
-  if (!BuildOpts.AddImplicitDtors)
+  if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
     return Scope;
 
   for (auto *DI : DS->decls())
     if (VarDecl *VD = dyn_cast<VarDecl>(DI))
       Scope = addLocalScopeForVarDecl(VD, Scope);
   return Scope;
 }
 
+bool CFGBuilder::hasTrivialDestructor(VarDecl *VD)
+{
+    // Check for const references bound to temporary. Set type to pointee.
+    QualType QT = VD->getType();
+    if (QT.getTypePtr()->isReferenceType()) {
+      // Attempt to determine whether this declaration lifetime-extends a
+      // temporary.
+      //
+      // FIXME: This is incorrect. Non-reference declarations can lifetime-extend
+      // temporaries, and a single declaration can extend multiple temporaries.
+      // We should look at the storage duration on each nested
+      // MaterializeTemporaryExpr instead.
+      const Expr *Init = VD->getInit();
+      if (!Init)
+        return true;
+      if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init))
+        Init = EWC->getSubExpr();
+      if (!isa<MaterializeTemporaryExpr>(Init))
+        return true;
+
+      // Lifetime-extending a temporary.
+      QT = getReferenceInitTemporaryType(*Context, Init);
+    }
+
+    // Check for constant size array. Set type to array element type.
+    while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
+      if (AT->getSize() == 0)
+        return true;
+      QT = AT->getElementType();
+    }
+
+    // Check if type is a C++ class with non-trivial destructor.
+    if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
+      return CD->hasTrivialDestructor();
+    return true;
+}
+
 /// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will
 /// create add scope for automatic objects and temporary objects bound to
 /// const reference. Will reuse Scope if not NULL.
 LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
                                                 LocalScope* Scope) {
-  if (!BuildOpts.AddImplicitDtors)
+  assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) && "AddImplicitDtors and AddLifetime cannot be used at the same time");
+  if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
     return Scope;
 
   // Check if variable is local.
@@ -1357,55 +1479,30 @@
   default: return Scope;
   }
 
-  // Check for const references bound to temporary. Set type to pointee.
-  QualType QT = VD->getType();
-  if (QT.getTypePtr()->isReferenceType()) {
-    // Attempt to determine whether this declaration lifetime-extends a
-    // temporary.
-    //
-    // FIXME: This is incorrect. Non-reference declarations can lifetime-extend
-    // temporaries, and a single declaration can extend multiple temporaries.
-    // We should look at the storage duration on each nested
-    // MaterializeTemporaryExpr instead.
-    const Expr *Init = VD->getInit();
-    if (!Init)
-      return Scope;
-    if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init))
-      Init = EWC->getSubExpr();
-    if (!isa<MaterializeTemporaryExpr>(Init))
-      return Scope;
-
-    // Lifetime-extending a temporary.
-    QT = getReferenceInitTemporaryType(*Context, Init);
-  }
-
-  // Check for constant size array. Set type to array element type.
-  while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
-    if (AT->getSize() == 0)
-      return Scope;
-    QT = AT->getElementType();
-  }
-
-  // Check if type is a C++ class with non-trivial destructor.
-  if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
-    if (!CD->hasTrivialDestructor()) {
+  if (BuildOpts.AddImplicitDtors) {
+    if (!hasTrivialDestructor(VD)) {
       // Add the variable to scope
       Scope = createOrReuseLocalScope(Scope);
       Scope->addVar(VD);
       ScopePos = Scope->begin();
     }
+    return Scope;
+  }
+
+  assert(BuildOpts.AddLifetime);
+  // Add the variable to scope
+  Scope = createOrReuseLocalScope(Scope);
+  Scope->addVar(VD);
+  ScopePos = Scope->begin();
   return Scope;
 }
 
 /// addLocalScopeAndDtors - For given statement add local scope for it and
 /// add destructors that will cleanup the scope. Will reuse Scope if not NULL.
 void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
-  if (!BuildOpts.AddImplicitDtors)
-    return;
-
   LocalScope::const_iterator scopeBeginPos = ScopePos;
   addLocalScopeForStmt(S);
-  addAutomaticObjDtors(ScopePos, scopeBeginPos, S);
+  addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
 }
 
 /// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for
@@ -1417,6 +1514,8 @@
 /// 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);
@@ -1809,7 +1908,7 @@
   // If there is no target for the break, then we are looking at an incomplete
   // AST.  This means that the CFG cannot be constructed.
   if (BreakJumpTarget.block) {
-    addAutomaticObjDtors(ScopePos, BreakJumpTarget.scopePosition, B);
+    addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
     addSuccessor(Block, BreakJumpTarget.block);
   } else
     badCFG = true;
@@ -1941,12 +2040,11 @@
 
 CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
   LocalScope::const_iterator scopeBeginPos = ScopePos;
-  if (BuildOpts.AddImplicitDtors) {
-    addLocalScopeForStmt(C);
-  }
+  addLocalScopeForStmt(C);
+
   if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) {
     // If the body ends with a ReturnStmt, the dtors will be added in VisitReturnStmt
-    addAutomaticObjDtors(ScopePos, scopeBeginPos, C);
+    addAutomaticObjHandling(ScopePos, scopeBeginPos, C);
   }
 
   CFGBlock *LastBlock = Block;
@@ -2173,7 +2271,7 @@
   if (VarDecl *VD = I->getConditionVariable()) {
     LocalScope::const_iterator BeginScopePos = ScopePos;
     addLocalScopeForVarDecl(VD);
-    addAutomaticObjDtors(ScopePos, BeginScopePos, I);
+    addAutomaticObjHandling(ScopePos, BeginScopePos, I);
   }
 
   // The block we were processing is now finished.  Make it the successor
@@ -2290,7 +2388,7 @@
   // Create the new block.
   Block = createBlock(false);
 
-  addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
+  addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R);
 
   // If the one of the destructors does not return, we already have the Exit
   // block as a successor.
@@ -2371,7 +2469,7 @@
     BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
   else {
     JumpTarget JT = I->second;
-    addAutomaticObjDtors(ScopePos, JT.scopePosition, G);
+    addAutomaticObjHandling(ScopePos, JT.scopePosition, G);
     addSuccessor(Block, JT.block);
   }
 
@@ -2396,7 +2494,7 @@
     addLocalScopeForVarDecl(VD);
   LocalScope::const_iterator ContinueScopePos = ScopePos;
 
-  addAutomaticObjDtors(ScopePos, save_scope_pos.get(), F);
+  addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
 
   // "for" is a control-flow statement.  Thus we stop processing the current
   // block.
@@ -2448,7 +2546,7 @@
    ContinueJumpTarget.block->setLoopTarget(F);
 
     // Loop body should end with destructor of Condition variable (if any).
-    addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F);
+    addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
 
     // If body is not a compound statement create implicit scope
     // and add destructors.
@@ -2735,7 +2833,7 @@
   LocalScope::const_iterator LoopBeginScopePos = ScopePos;
   if (VarDecl *VD = W->getConditionVariable()) {
     addLocalScopeForVarDecl(VD);
-    addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
+    addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
   }
 
   // "while" is a control-flow statement.  Thus we stop processing the current
@@ -2770,7 +2868,7 @@
     BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
 
     // Loop body should end with destructor of Condition variable (if any).
-    addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
+    addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
 
     // If body is not a compound statement create implicit scope
     // and add destructors.
@@ -3013,7 +3111,7 @@
   // If there is no target for the continue, then we are looking at an
   // incomplete AST.  This means the CFG cannot be constructed.
   if (ContinueJumpTarget.block) {
-    addAutomaticObjDtors(ScopePos, ContinueJumpTarget.scopePosition, C);
+    addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition, C);
     addSuccessor(Block, ContinueJumpTarget.block);
   } else
     badCFG = true;
@@ -3064,7 +3162,7 @@
   if (VarDecl *VD = Terminator->getConditionVariable()) {
     LocalScope::const_iterator SwitchBeginScopePos = ScopePos;
     addLocalScopeForVarDecl(VD);
-    addAutomaticObjDtors(ScopePos, SwitchBeginScopePos, Terminator);
+    addAutomaticObjHandling(ScopePos, SwitchBeginScopePos, Terminator);
   }
 
   if (Block) {
@@ -3347,7 +3445,7 @@
   if (VarDecl *VD = CS->getExceptionDecl()) {
     LocalScope::const_iterator BeginScopePos = ScopePos;
     addLocalScopeForVarDecl(VD);
-    addAutomaticObjDtors(ScopePos, BeginScopePos, CS);
+    addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
   }
 
   if (CS->getHandlerBlock())
@@ -3401,7 +3499,7 @@
     addLocalScopeForStmt(Begin);
   if (Stmt *End = S->getEndStmt())
     addLocalScopeForStmt(End);
-  addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
+  addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
 
   LocalScope::const_iterator ContinueScopePos = ScopePos;
 
@@ -3868,6 +3966,7 @@
     case CFGElement::Statement:
     case CFGElement::Initializer:
     case CFGElement::NewAllocator:
+    case CFGElement::LifetimeEnds:
       llvm_unreachable("getDestructorDecl should only be used with "
                        "ImplicitDtors");
     case CFGElement::AutomaticObjectDtor: {
@@ -4268,6 +4367,13 @@
     OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
     OS << " (Implicit destructor)\n";
 
+  } else if (Optional<CFGLifetimeEnds> DE =
+                       E.getAs<CFGLifetimeEnds>()) {
+    const VarDecl *VD = DE->getVarDecl();
+    Helper.handleDecl(VD, OS);
+
+    OS << " (Lifetime ends)\n";
+
   } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
     OS << "CFGNewAllocator(";
     if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())
Index: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp
+++ lib/Analysis/AnalysisDeclContext.cpp
@@ -67,6 +67,7 @@
                                                        bool addImplicitDtors,
                                                        bool addInitializers,
                                                        bool addTemporaryDtors,
+                                                       bool addLifetime,
                                                        bool synthesizeBodies,
                                                        bool addStaticInitBranch,
                                                        bool addCXXNewAllocator,
@@ -77,6 +78,7 @@
   cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
   cfgBuildOptions.AddInitializers = addInitializers;
   cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
+  cfgBuildOptions.AddLifetime = addLifetime;
   cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
   cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
 }
Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
===================================================================
--- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -201,9 +201,15 @@
   /// Controls which C++ member functions will be considered for inlining.
   CXXInlineableMemberKind CXXMemberInliningMode;
   
+  /// \sa includeImplicitDtorsInCFG
+  Optional<bool> IncludeImplicitDtorsInCFG;
+
   /// \sa includeTemporaryDtorsInCFG
   Optional<bool> IncludeTemporaryDtorsInCFG;
   
+  /// \sa IncludeLifetimeInCFG
+  Optional<bool> IncludeLifetimeInCFG;
+
   /// \sa mayInlineCXXStandardLibrary
   Optional<bool> InlineCXXStandardLibrary;
   
@@ -388,6 +394,19 @@
   /// accepts the values "true" and "false".
   bool includeTemporaryDtorsInCFG();
 
+  /// Returns whether or not implicit destructors for C++ objects should
+  /// be included in the CFG.
+  ///
+  /// This is controlled by the 'cfg-implicit-dtors' config option, which
+  /// accepts the values "true" and "false".
+  bool includeImplicitDtorsInCFG();
+
+  /// Returns whether or not end-of-lifetime information should be included in the CFG.
+  ///
+  /// This is controlled by the 'cfg-lifetime' config option, which accepts
+  /// the values "true" and "false".
+  bool includeLifetimeInCFG();
+
   /// Returns whether or not C++ standard library functions may be considered
   /// for inlining.
   ///
Index: include/clang/Analysis/CFG.h
===================================================================
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -57,6 +57,7 @@
     Statement,
     Initializer,
     NewAllocator,
+    LifetimeEnds,
     // dtor kind
     AutomaticObjectDtor,
     DeleteDtor,
@@ -166,6 +167,28 @@
   }
 };
 
+/// Represents the point where the lifetime of an automatic object ends
+class CFGLifetimeEnds : public CFGElement {
+public:
+  explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt)
+    : CFGElement(LifetimeEnds, var, stmt) {}
+
+  const VarDecl *getVarDecl() const {
+    return static_cast<VarDecl*>(Data1.getPointer());
+  }
+
+  const Stmt *getTriggerStmt() const {
+    return static_cast<Stmt*>(Data2.getPointer());
+  }
+
+private:
+  friend class CFGElement;
+  CFGLifetimeEnds() {}
+  static bool isKind(const CFGElement &elem) {
+    return elem.getKind() == LifetimeEnds;
+  }
+};
+
 /// CFGImplicitDtor - Represents C++ object destructor implicitly generated
 /// by compiler on various occasions.
 class CFGImplicitDtor : public CFGElement {
@@ -682,6 +705,10 @@
     Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
   }
 
+  void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
+    Elements.push_back(CFGLifetimeEnds(VD, S), C);
+  }
+
   void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
     Elements.push_back(CFGDeleteDtor(RD, DE), C);
   }
@@ -698,6 +725,19 @@
     *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;
+  }
 };
 
 /// \brief CFGCallback defines methods that should be called when a logical
@@ -734,6 +774,7 @@
     bool AddEHEdges;
     bool AddInitializers;
     bool AddImplicitDtors;
+    bool AddLifetime;
     bool AddTemporaryDtors;
     bool AddStaticInitBranches;
     bool AddCXXNewAllocator;
@@ -755,8 +796,10 @@
 
     BuildOptions()
       : forcedBlkExprs(nullptr), Observer(nullptr),
-        PruneTriviallyFalseEdges(true), AddEHEdges(false),
+        PruneTriviallyFalseEdges(true),
+        AddEHEdges(false),
         AddInitializers(false), AddImplicitDtors(false),
+        AddLifetime(false),
         AddTemporaryDtors(false), AddStaticInitBranches(false),
         AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {}
   };
Index: include/clang/Analysis/AnalysisContext.h
===================================================================
--- include/clang/Analysis/AnalysisContext.h
+++ include/clang/Analysis/AnalysisContext.h
@@ -425,6 +425,7 @@
                              bool addImplicitDtors = false,
                              bool addInitializers = false,
                              bool addTemporaryDtors = false,
+                             bool addLifetime = false,
                              bool synthesizeBodies = false,
                              bool addStaticInitBranches = false,
                              bool addCXXNewAllocator = true,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to