From 046e79a425bfa82b480b8a07ce11d96391fa0a9b Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Wed, 17 Jul 2013 08:33:58 +0000 Subject: [PATCH] [analyzer] Add very limited support for temporary destructors Summary: This patch enables ExprEndgine to reason about temporary object destructors. However, these destructor calls are never inlined, since this feature is still broken. Still, this is sufficient to properly handle noreturn temporary destructors and close bug #15599. I have also enabled the cfg-temporary-dtors analyzer option by default. Reviewers: jordan_rose CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1131 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186498 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp | 2 +- lib/StaticAnalyzer/Core/ExprEngine.cpp | 10 +++- .../Core/ExprEngineCallAndReturn.cpp | 6 +++ test/Analysis/analyzer-config.c | 2 +- test/Analysis/analyzer-config.cpp | 2 +- test/Analysis/dtor.cpp | 15 ++++++ test/Analysis/temp-obj-dtors-cfg-output.cpp | 51 +++++++++++++++++++ 7 files changed, 84 insertions(+), 4 deletions(-) diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 9dcf58babd..93b620410b 100644 --- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -119,7 +119,7 @@ bool AnalyzerOptions::getBooleanOption(Optional &V, StringRef Name, bool AnalyzerOptions::includeTemporaryDtorsInCFG() { return getBooleanOption(IncludeTemporaryDtorsInCFG, "cfg-temporary-dtors", - /* Default = */ false); + /* Default = */ true); } bool AnalyzerOptions::mayInlineCXXStandardLibrary() { diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 59c66b83c7..39ca429e19 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -589,7 +589,15 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, 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) { diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index b76649e6fc..aa7593e721 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -804,6 +804,12 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D, AnalysisDeclContextManager &ADCMgr = AMgr.getAnalysisDeclContextManager(); AnalysisDeclContext *CalleeADC = ADCMgr.getContext(D); + // Temporary object destructor processing is currently broken, so we never + // inline them. + // FIME: Remove this once temp destructors are working. + if ((*currBldrCtx->getBlock())[currStmtIdx].getAs()) + 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. diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c index 55b1df9ca8..c80eb164b9 100644 --- a/test/Analysis/analyzer-config.c +++ b/test/Analysis/analyzer-config.c @@ -6,7 +6,7 @@ void foo() { bar(); } // 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 diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp index 521344a511..4160508a38 100644 --- a/test/Analysis/analyzer-config.cpp +++ b/test/Analysis/analyzer-config.cpp @@ -17,7 +17,7 @@ public: // 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 diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp index 58bdcea631..80b3157069 100644 --- a/test/Analysis/dtor.cpp +++ b/test/Analysis/dtor.cpp @@ -416,4 +416,19 @@ namespace NoReturn { 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 + } } diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp index 1ddccb704b..ff68a876e9 100644 --- a/test/Analysis/temp-obj-dtors-cfg-output.cpp +++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -108,6 +108,24 @@ TestCtorInits::TestCtorInits() : 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 @@ TestCtorInits::TestCtorInits() // 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 -- 2.40.0