Now that the first part of the patch has landed, I'd like to turn our 
attention to the second one. :)

Hi jordan_rose,

http://llvm-reviews.chandlerc.com/D1259

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D1259?vs=3368&id=3697#toc

Files:
  lib/Analysis/CFG.cpp
  lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  test/Analysis/analyzer-config.c
  test/Analysis/analyzer-config.cpp
  test/Analysis/dtor.cpp
  test/Analysis/temp-obj-dtors-cfg-output.cpp
  test/Analysis/temporaries.cpp
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -3765,8 +3765,9 @@
 
   } else if (Optional<CFGTemporaryDtor> TE = E.getAs<CFGTemporaryDtor>()) {
     const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
-    OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()";
-    OS << " (Temporary object destructor)\n";
+    OS << "~";
+    BT->getType().print(OS, PrintingPolicy(Helper->getLangOpts()));
+    OS << "() (Temporary object destructor)\n";
   }
 }
 
Index: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
===================================================================
--- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -119,7 +119,7 @@
 bool AnalyzerOptions::includeTemporaryDtorsInCFG() {
   return getBooleanOption(IncludeTemporaryDtorsInCFG,
                           "cfg-temporary-dtors",
-                          /* Default = */ false);
+                          /* Default = */ true);
 }
 
 bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -601,7 +601,15 @@
 
 void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
                                       ExplodedNode *Pred,
-                                      ExplodedNodeSet &Dst) {}
+                                      ExplodedNodeSet &Dst) {
+
+  QualType varType = D.getBindTemporaryExpr()->getSubExpr()->getType();
+
+  // FIXME: Inlining of temporary destructors is not supported yet anyway, so we
+  // just put a NULL region for now. This will need to be changed later.
+  VisitCXXDestructor(varType, NULL, D.getBindTemporaryExpr(),
+                     /*IsBase=*/ false, Pred, Dst);
+}
 
 void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
                        ExplodedNodeSet &DstTop) {
@@ -1347,10 +1355,14 @@
   SVal TrueVal = SVB.makeTruthVal(true);
   SVal FalseVal = SVB.makeTruthVal(false);
 
-  // Resolve the condition in the precense of nested '||' and '&&'.
   if (const Expr *Ex = dyn_cast<Expr>(Condition))
     Condition = Ex->IgnoreParens();
-  Condition = ResolveCondition(Condition, BldCtx.getBlock());
+
+  // If the value is already available, we don't need to do anything.
+  if(Pred->getState()->getSVal(Condition, Pred->getLocationContext()).isUnknownOrUndef()) {
+    // Resolve the condition in the presence of nested '||' and '&&'.
+    Condition = ResolveCondition(Condition, BldCtx.getBlock());
+  }
 
   // Cast truth values to the correct type.
   if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
@@ -1360,7 +1372,6 @@
                             getContext().getLogicalOperationType());
   }
 
-
   PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
                                 Condition->getLocStart(),
                                 "Error evaluating branch");
Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -96,7 +96,11 @@
 
   while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) {
     Ty = AT->getElementType();
-    LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue);
+    // FIXME: The if test is just a temporary workaround, because
+    // ProcessTemporaryDtor sends us NULL regions. It will not be necessary once
+    // we can properly process temporary destructors.
+    if (LValue.getAsRegion())
+      LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue);
   }
 
   return LValue;
Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -807,6 +807,12 @@
   AnalysisDeclContextManager &ADCMgr = AMgr.getAnalysisDeclContextManager();
   AnalysisDeclContext *CalleeADC = ADCMgr.getContext(D);
 
+  // Temporary object destructor processing is currently broken, so we never
+  // inline them.
+  // FIXME: Remove this once temp destructors are working.
+  if ((*currBldrCtx->getBlock())[currStmtIdx].getAs<CFGTemporaryDtor>())
+    return false;
+
   // The auto-synthesized bodies are essential to inline as they are
   // usually small and commonly used. Note: we should do this check early on to
   // ensure we always inline these calls.
Index: test/Analysis/analyzer-config.c
===================================================================
--- test/Analysis/analyzer-config.c
+++ test/Analysis/analyzer-config.c
@@ -6,7 +6,7 @@
 
 // CHECK: [config]
 // CHECK-NEXT: cfg-conditional-static-initializers = true
-// CHECK-NEXT: cfg-temporary-dtors = false
+// CHECK-NEXT: cfg-temporary-dtors = true
 // CHECK-NEXT: faux-bodies = true
 // CHECK-NEXT: graph-trim-interval = 1000
 // CHECK-NEXT: ipa = dynamic-bifurcate
Index: test/Analysis/analyzer-config.cpp
===================================================================
--- test/Analysis/analyzer-config.cpp
+++ test/Analysis/analyzer-config.cpp
@@ -17,7 +17,7 @@
 // CHECK-NEXT: c++-stdlib-inlining = true
 // CHECK-NEXT: c++-template-inlining = true
 // CHECK-NEXT: cfg-conditional-static-initializers = true
-// CHECK-NEXT: cfg-temporary-dtors = false
+// CHECK-NEXT: cfg-temporary-dtors = true
 // CHECK-NEXT: faux-bodies = true
 // CHECK-NEXT: graph-trim-interval = 1000
 // CHECK-NEXT: ipa = dynamic-bifurcate
Index: test/Analysis/dtor.cpp
===================================================================
--- test/Analysis/dtor.cpp
+++ test/Analysis/dtor.cpp
@@ -416,6 +416,21 @@
     f(&x);
     *x = 47; // no warning
   }
+
+  void g2(int *x) {
+    if (! x) NR();
+    *x = 47; // no warning
+  }
+
+  void f3(int **x) {
+    NR();
+  }
+
+  void g3() {
+    int *x;
+    f3(&x);
+    *x = 47; // no warning
+  }
 }
 
 namespace PseudoDtor {
Index: test/Analysis/temp-obj-dtors-cfg-output.cpp
===================================================================
--- test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -108,6 +108,24 @@
   : a(int(A()) + int(B()))
   , b() {}
 
+class NoReturn {
+public:
+  ~NoReturn() __attribute__((noreturn));
+  void f();
+};
+
+void test_noreturn1() {
+  int a;
+  NoReturn().f();
+  int b;
+}
+
+void test_noreturn2() {
+  int a;
+  NoReturn(), 47;
+  int b;
+}
+
 // CHECK:   [B1 (ENTRY)]
 // CHECK:     Succs (1): B0
 // CHECK:   [B0 (EXIT)]
@@ -846,3 +864,36 @@
 // CHECK:   [B0 (EXIT)]
 // CHECK:     Preds (1): B1
 
+// CHECK:   [B3 (ENTRY)]
+// CHECK:     Succs (1): B2
+// CHECK:   [B1]
+// CHECK:     1: int b;
+// CHECK:     Succs (1): B0
+// CHECK:   [B2]
+// CHECK:     1: int a;
+// CHECK:     2: NoReturn() (CXXConstructExpr, class NoReturn)
+// CHECK:     3: [B2.2] (BindTemporary)
+// CHECK:     4: [B2.3].f
+// CHECK:     5: [B2.4]()
+// CHECK:     6: ~NoReturn() (Temporary object destructor)
+// CHECK:     Preds (1): B3
+// CHECK:     Succs (1): B0
+// CHECK:   [B0 (EXIT)]
+// CHECK:     Preds (2): B1 B2
+
+// CHECK:   [B3 (ENTRY)]
+// CHECK:     Succs (1): B2
+// CHECK:   [B1]
+// CHECK:     1: int b;
+// CHECK:     Succs (1): B0
+// CHECK:   [B2]
+// CHECK:     1: int a;
+// CHECK:     2: NoReturn() (CXXConstructExpr, class NoReturn)
+// CHECK:     3: [B2.2] (BindTemporary)
+// CHECK:     4: 47
+// CHECK:     5: ... , [B2.4]
+// CHECK:     6: ~NoReturn() (Temporary object destructor)
+// CHECK:     Preds (1): B3
+// CHECK:     Succs (1): B0
+// CHECK:   [B0 (EXIT)]
+// CHECK:     Preds (2): B1 B2
Index: test/Analysis/temporaries.cpp
===================================================================
--- test/Analysis/temporaries.cpp
+++ test/Analysis/temporaries.cpp
@@ -123,22 +123,57 @@
     }
   }
 
-  void testConsistency(int i) {
-    struct NoReturnDtor {
-      ~NoReturnDtor() __attribute__((noreturn));
-    };
-    extern bool check(const NoReturnDtor &);
-    
+  struct NoReturnDtor {
+    ~NoReturnDtor() __attribute__((noreturn));
+  };
+  extern bool check(const NoReturnDtor &);
+
+  void testConsistencyIf(int i) {
     if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
       clang_analyzer_eval(true); // expected-warning{{TRUE}}
 
     if (i != 5)
       return;
     if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) {
-      // FIXME: Should be no-warning, because the noreturn destructor should
-      // fire on all paths.
+      clang_analyzer_eval(true); // no warning, unreachable code
+    }
+  }
+
+  void testConsistencyTernary(int i) {
+    (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
+
+    clang_analyzer_eval(true);  // expected-warning{{TRUE}}
+
+    if (i != 5)
+      return;
+
+    (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
+
+    clang_analyzer_eval(true); // no warning, unreachable code
+  }
+
+  void testConsistencyNested(int i) {
+    extern bool compute(bool);
+
+    if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
+      clang_analyzer_eval(true);  // expected-warning{{TRUE}}
+
+    if (i != 5)
+      return;
+
+    if (compute(i == 5 &&
+                (i == 4 || compute(true) ||
+                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
+        i != 4) {
       clang_analyzer_eval(true); // expected-warning{{TRUE}}
     }
+
+    if (compute(i == 5 &&
+                (i == 4 || i == 4 ||
+                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
+        i != 4) {
+      clang_analyzer_eval(true); // no warning, unreachable code
+    }
   }
 }
 
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to