diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-02-23 22:20:39 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-02-23 22:20:39 +0000 |
commit | 783a4578c14bd4a98039ae6297fe9173cd1afd51 (patch) | |
tree | 1bcb335c1dcab7bc4fdae5f2322f719417da0ae4 /clang/lib/Analysis/CFG.cpp | |
parent | db53d1847bcc7900ca351144806c93375f4bd3e1 (diff) | |
download | bcm5719-llvm-783a4578c14bd4a98039ae6297fe9173cd1afd51.tar.gz bcm5719-llvm-783a4578c14bd4a98039ae6297fe9173cd1afd51.zip |
[CFG] [analyzer] NFC: Allow more complicated construction contexts.
ConstructionContexts introduced in D42672 are an additional piece of information
included with CFGConstructor elements that help the client of the CFG (such as
the Static Analyzer) understand where the newly constructed object is stored.
The patch refactors the ConstructionContext class to prepare for including
multi-layered contexts that are being constructed gradually, layer-by-layer,
as the AST is traversed.
Differential Revision: https://reviews.llvm.org/D43428
llvm-svn: 325966
Diffstat (limited to 'clang/lib/Analysis/CFG.cpp')
-rw-r--r-- | clang/lib/Analysis/CFG.cpp | 74 |
1 files changed, 50 insertions, 24 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index d2d1917c468..c65a6521721 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -475,7 +475,8 @@ class CFGBuilder { // Information about the currently visited C++ object construction site. // This is set in the construction trigger and read when the constructor // itself is being visited. - ConstructionContext CurrentConstructionContext = {}; + llvm::DenseMap<CXXConstructExpr *, const ConstructionContext *> + ConstructionContextMap{}; bool badCFG = false; const CFG::BuildOptions &BuildOpts; @@ -654,12 +655,12 @@ private: // to the trigger statement. The construction context will be unset once // it is consumed when the CFG building procedure processes the // construct-expression and adds the respective CFGConstructor element. - void EnterConstructionContextIfNecessary( - ConstructionContext::TriggerTy Trigger, Stmt *Child); + void findConstructionContexts(const ConstructionContext *ContextSoFar, + Stmt *Child); // Unset the construction context after consuming it. This is done immediately // after adding the CFGConstructor element, so there's no need to // do this manually in every Visit... function. - void ExitConstructionContext(); + void cleanupConstructionContext(CXXConstructExpr *CE); void autoCreateBlock() { if (!Block) Block = createBlock(); } CFGBlock *createBlock(bool add_successor = true); @@ -702,10 +703,9 @@ private: void appendConstructor(CFGBlock *B, CXXConstructExpr *CE) { if (BuildOpts.AddRichCXXConstructors) { - if (!CurrentConstructionContext.isNull()) { - B->appendConstructor(CE, CurrentConstructionContext, - cfg->getBumpVectorContext()); - ExitConstructionContext(); + if (const ConstructionContext *CC = ConstructionContextMap.lookup(CE)) { + B->appendConstructor(CE, CC, cfg->getBumpVectorContext()); + cleanupConstructionContext(CE); return; } } @@ -1148,25 +1148,38 @@ static const VariableArrayType *FindVA(const Type *t) { return nullptr; } -void CFGBuilder::EnterConstructionContextIfNecessary( - ConstructionContext::TriggerTy Trigger, Stmt *Child) { +void CFGBuilder::findConstructionContexts( + const ConstructionContext *ContextSoFar, Stmt *Child) { if (!BuildOpts.AddRichCXXConstructors) return; if (!Child) return; - if (isa<CXXConstructExpr>(Child)) { - assert(CurrentConstructionContext.isNull() && - "Already within a construction context!"); - CurrentConstructionContext = ConstructionContext(Trigger); + if (auto *CE = dyn_cast<CXXConstructExpr>(Child)) { + if (const ConstructionContext *PreviousContext = + ConstructionContextMap.lookup(CE)) { + // We might have visited this child when we were finding construction + // contexts within its parents. + assert(PreviousContext->isStrictlyMoreSpecificThan(ContextSoFar) && + "Already within a different construction context!"); + } else { + ConstructionContextMap[CE] = ContextSoFar; + } } else if (auto *Cleanups = dyn_cast<ExprWithCleanups>(Child)) { - EnterConstructionContextIfNecessary(Trigger, Cleanups->getSubExpr()); + findConstructionContexts(ContextSoFar, Cleanups->getSubExpr()); + } else if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Child)) { + findConstructionContexts( + ConstructionContext::create(cfg->getBumpVectorContext(), BTE, + ContextSoFar), + BTE->getSubExpr()); } } -void CFGBuilder::ExitConstructionContext() { - assert(!CurrentConstructionContext.isNull() && +void CFGBuilder::cleanupConstructionContext(CXXConstructExpr *CE) { + assert(BuildOpts.AddRichCXXConstructors && + "We should not be managing construction contexts!"); + assert(ConstructionContextMap.count(CE) && "Cannot exit construction context without the context!"); - CurrentConstructionContext = ConstructionContext(); + ConstructionContextMap.erase(CE); } @@ -1250,6 +1263,10 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { // Create an empty entry block that has no predecessors. cfg->setEntry(createBlock()); + if (BuildOpts.AddRichCXXConstructors) + assert(ConstructionContextMap.empty() && + "Not all construction contexts were cleaned up!"); + return std::move(cfg); } @@ -1297,7 +1314,9 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { appendInitializer(Block, I); if (Init) { - EnterConstructionContextIfNecessary(I, Init); + findConstructionContexts( + ConstructionContext::create(cfg->getBumpVectorContext(), I), + Init); if (HasTemporaries) { // For expression with temporaries go directly to subexpression to omit @@ -2383,7 +2402,9 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { autoCreateBlock(); appendStmt(Block, DS); - EnterConstructionContextIfNecessary(DS, Init); + findConstructionContexts( + ConstructionContext::create(cfg->getBumpVectorContext(), DS), + Init); // Keep track of the last non-null block, as 'Block' can be nulled out // if the initializer expression is something like a 'while' in a @@ -2575,7 +2596,9 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) { addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R); - EnterConstructionContextIfNecessary(R, R->getRetValue()); + findConstructionContexts( + ConstructionContext::create(cfg->getBumpVectorContext(), R), + R->getRetValue()); // If the one of the destructors does not return, we already have the Exit // block as a successor. @@ -3923,7 +3946,9 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, autoCreateBlock(); appendStmt(Block, E); - EnterConstructionContextIfNecessary(E, E->getSubExpr()); + findConstructionContexts( + ConstructionContext::create(cfg->getBumpVectorContext(), E), + E->getSubExpr()); // We do not want to propagate the AlwaysAdd property. asc = asc.withAlwaysAdd(false); @@ -3944,8 +3969,9 @@ CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE, autoCreateBlock(); appendStmt(Block, NE); - EnterConstructionContextIfNecessary( - NE, const_cast<CXXConstructExpr *>(NE->getConstructExpr())); + findConstructionContexts( + ConstructionContext::create(cfg->getBumpVectorContext(), NE), + const_cast<CXXConstructExpr *>(NE->getConstructExpr())); if (NE->getInitializer()) Block = Visit(NE->getInitializer()); |