diff options
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 21 | ||||
-rw-r--r-- | clang/test/Analysis/temporaries.cpp | 21 |
2 files changed, 36 insertions, 6 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index e837f5b740a..4743bd6e602 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -681,8 +681,11 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, StmtBldr.generateNode(D.getBindTemporaryExpr(), Pred, State); QualType varType = D.getBindTemporaryExpr()->getSubExpr()->getType(); - assert(CleanDtorState.size() == 1); - ExplodedNode *CleanPred = *CleanDtorState.begin(); + // FIXME: Currently CleanDtorState can be empty here due to temporaries being + // bound to default parameters. + assert(CleanDtorState.size() <= 1); + ExplodedNode *CleanPred = + CleanDtorState.empty() ? Pred : *CleanDtorState.begin(); // 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, nullptr, D.getBindTemporaryExpr(), @@ -718,10 +721,16 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, StmtNodeBuilder StmtBldr(PreVisit, Dst, *currBldrCtx); for (ExplodedNode *Node : PreVisit) { ProgramStateRef State = Node->getState(); - assert(!State->contains<InitializedTemporariesSet>( - std::make_pair(BTE, Node->getStackFrame()))); - State = State->add<InitializedTemporariesSet>( - std::make_pair(BTE, Node->getStackFrame())); + + if (!State->contains<InitializedTemporariesSet>( + std::make_pair(BTE, Node->getStackFrame()))) { + // FIXME: Currently the state might already contain the marker due to + // incorrect handling of temporaries bound to default parameters; for + // those, we currently skip the CXXBindTemporaryExpr but rely on adding + // temporary destructor nodes. + State = State->add<InitializedTemporariesSet>( + std::make_pair(BTE, Node->getStackFrame())); + } StmtBldr.generateNode(BTE, Node, State); } } diff --git a/clang/test/Analysis/temporaries.cpp b/clang/test/Analysis/temporaries.cpp index b1099d1f207..6e476339cb7 100644 --- a/clang/test/Analysis/temporaries.cpp +++ b/clang/test/Analysis/temporaries.cpp @@ -398,6 +398,27 @@ namespace destructors { void testDefaultParameters() { f(); } + + struct DefaultParam { + DefaultParam(int, const Dtor& d = Dtor()); + ~DefaultParam(); + }; + void testDefaultParamConstructorsInLoops() { + while (true) { + // FIXME: This exact pattern triggers the temporary cleanup logic + // to fail when adding a 'clean' state. + DefaultParam(42); + DefaultParam(42); + } + } + void testDefaultParamConstructorsInTernariesInLoops(bool value) { + while (true) { + // FIXME: This exact pattern triggers the temporary cleanup logic + // to visit the bind-temporary logic with a state that already has that + // temporary marked as executed. + value ? DefaultParam(42) : DefaultParam(42); + } + } #endif // TEMPORARY_DTORS } |