summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis/CFG.cpp
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-02-23 22:20:39 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-02-23 22:20:39 +0000
commit783a4578c14bd4a98039ae6297fe9173cd1afd51 (patch)
tree1bcb335c1dcab7bc4fdae5f2322f719417da0ae4 /clang/lib/Analysis/CFG.cpp
parentdb53d1847bcc7900ca351144806c93375f4bd3e1 (diff)
downloadbcm5719-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.cpp74
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());
OpenPOWER on IntegriCloud