summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-02-27 20:03:35 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-02-27 20:03:35 +0000
commit4068481bdb115194fe02c88f6b6dc12ebb4c9ddd (patch)
treefb634591e544128733b75f68d4f72c2f88ce1987 /clang/lib/Analysis
parent301991080e24ac402793ca6684daa2fc70647f8a (diff)
downloadbcm5719-llvm-4068481bdb115194fe02c88f6b6dc12ebb4c9ddd.tar.gz
bcm5719-llvm-4068481bdb115194fe02c88f6b6dc12ebb4c9ddd.zip
[CFG] NFC: Refactor ConstructionContext into a finite set of cases.
ConstructionContext is moved into a separate translation unit and is separated into multiple classes. The "old" "raw" ConstructionContext is renamed into ConstructionContextLayer - which corresponds to the idea of building the context gradually layer-by-layer, but it isn't easy to use in the clients. Once CXXConstructExpr is reached, layers that we've gathered so far are transformed into the actual, "new-style" "flat" ConstructionContext, which is put into the CFGConstructor element and has no layers whatsoever (until it actually needs them, eg. aggregate initialization). The new-style ConstructionContext is instead presented as a variety of sub-classes that enumerate different ways of constructing an object in C++. There are 5 of these supported for now, which is around a half of what needs to be supported. The layer-by-layer buildup process is still a little bit weird, but it hides all the weirdness in one place, that sounds like a good thing. Differential Revision: https://reviews.llvm.org/D43533 llvm-svn: 326238
Diffstat (limited to 'clang/lib/Analysis')
-rw-r--r--clang/lib/Analysis/CFG.cpp118
-rw-r--r--clang/lib/Analysis/CMakeLists.txt1
-rw-r--r--clang/lib/Analysis/ConstructionContext.cpp92
3 files changed, 168 insertions, 43 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 1cf70631172..727c304f7a3 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -29,6 +29,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Analysis/ConstructionContext.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/LLVM.h"
@@ -475,7 +476,7 @@ 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.
- llvm::DenseMap<CXXConstructExpr *, const ConstructionContext *>
+ llvm::DenseMap<CXXConstructExpr *, const ConstructionContextLayer *>
ConstructionContextMap;
bool badCFG = false;
@@ -652,18 +653,19 @@ private:
return Block;
}
- // Remember to apply \p CC when constructing the CFG element for \p CE.
- void consumeConstructionContext(const ConstructionContext *CC,
+ // Remember to apply the construction context based on the current \p Layer
+ // when constructing the CFG element for \p CE.
+ void consumeConstructionContext(const ConstructionContextLayer *Layer,
CXXConstructExpr *CE);
- // Scan the child statement \p Child to find the constructor that might
- // have been directly triggered by the current node, \p Trigger. If such
- // constructor has been found, set current construction context to point
- // 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 findConstructionContexts(const ConstructionContext *ContextSoFar,
+ // Scan \p Child statement to find constructors in it, while keeping in mind
+ // that its parent statement is providing a partial construction context
+ // described by \p Layer. If a constructor is found, it would be assigned
+ // the context based on the layer. If an additional construction context layer
+ // is found, the function recurses into that.
+ void findConstructionContexts(const ConstructionContextLayer *Layer,
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.
@@ -710,7 +712,11 @@ private:
void appendConstructor(CFGBlock *B, CXXConstructExpr *CE) {
if (BuildOpts.AddRichCXXConstructors) {
- if (const ConstructionContext *CC = ConstructionContextMap.lookup(CE)) {
+ if (const ConstructionContextLayer *Layer =
+ ConstructionContextMap.lookup(CE)) {
+ const ConstructionContext *CC =
+ ConstructionContext::createFromLayers(cfg->getBumpVectorContext(),
+ Layer);
B->appendConstructor(CE, CC, cfg->getBumpVectorContext());
cleanupConstructionContext(CE);
return;
@@ -1155,20 +1161,21 @@ static const VariableArrayType *FindVA(const Type *t) {
return nullptr;
}
-void CFGBuilder::consumeConstructionContext(const ConstructionContext *CC, CXXConstructExpr *CE) {
- if (const ConstructionContext *PreviousContext =
+void CFGBuilder::consumeConstructionContext(
+ const ConstructionContextLayer *Layer, CXXConstructExpr *CE) {
+ if (const ConstructionContextLayer *PreviouslyStoredLayer =
ConstructionContextMap.lookup(CE)) {
// We might have visited this child when we were finding construction
// contexts within its parents.
- assert(PreviousContext->isStrictlyMoreSpecificThan(CC) &&
+ assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
"Already within a different construction context!");
} else {
- ConstructionContextMap[CE] = CC;
+ ConstructionContextMap[CE] = Layer;
}
}
void CFGBuilder::findConstructionContexts(
- const ConstructionContext *ContextSoFar, Stmt *Child) {
+ const ConstructionContextLayer *Layer, Stmt *Child) {
if (!BuildOpts.AddRichCXXConstructors)
return;
@@ -1178,36 +1185,36 @@ void CFGBuilder::findConstructionContexts(
switch(Child->getStmtClass()) {
case Stmt::CXXConstructExprClass:
case Stmt::CXXTemporaryObjectExprClass: {
- consumeConstructionContext(ContextSoFar, cast<CXXConstructExpr>(Child));
+ consumeConstructionContext(Layer, cast<CXXConstructExpr>(Child));
break;
}
case Stmt::ExprWithCleanupsClass: {
auto *Cleanups = cast<ExprWithCleanups>(Child);
- findConstructionContexts(ContextSoFar, Cleanups->getSubExpr());
+ findConstructionContexts(Layer, Cleanups->getSubExpr());
break;
}
case Stmt::CXXFunctionalCastExprClass: {
auto *Cast = cast<CXXFunctionalCastExpr>(Child);
- findConstructionContexts(ContextSoFar, Cast->getSubExpr());
+ findConstructionContexts(Layer, Cast->getSubExpr());
break;
}
case Stmt::ImplicitCastExprClass: {
auto *Cast = cast<ImplicitCastExpr>(Child);
- findConstructionContexts(ContextSoFar, Cast->getSubExpr());
+ findConstructionContexts(Layer, Cast->getSubExpr());
break;
}
case Stmt::CXXBindTemporaryExprClass: {
auto *BTE = cast<CXXBindTemporaryExpr>(Child);
findConstructionContexts(
- ConstructionContext::create(cfg->getBumpVectorContext(), BTE,
- ContextSoFar),
+ ConstructionContextLayer::create(cfg->getBumpVectorContext(),
+ BTE, Layer),
BTE->getSubExpr());
break;
}
case Stmt::ConditionalOperatorClass: {
auto *CO = cast<ConditionalOperator>(Child);
- findConstructionContexts(ContextSoFar, CO->getLHS());
- findConstructionContexts(ContextSoFar, CO->getRHS());
+ findConstructionContexts(Layer, CO->getLHS());
+ findConstructionContexts(Layer, CO->getRHS());
break;
}
default:
@@ -1356,7 +1363,7 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
if (Init) {
findConstructionContexts(
- ConstructionContext::create(cfg->getBumpVectorContext(), I),
+ ConstructionContextLayer::create(cfg->getBumpVectorContext(), I),
Init);
if (HasTemporaries) {
@@ -2448,7 +2455,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
appendStmt(Block, DS);
findConstructionContexts(
- ConstructionContext::create(cfg->getBumpVectorContext(), DS),
+ ConstructionContextLayer::create(cfg->getBumpVectorContext(), DS),
Init);
// Keep track of the last non-null block, as 'Block' can be nulled out
@@ -2642,7 +2649,7 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R);
findConstructionContexts(
- ConstructionContext::create(cfg->getBumpVectorContext(), R),
+ ConstructionContextLayer::create(cfg->getBumpVectorContext(), R),
R->getRetValue());
// If the one of the destructors does not return, we already have the Exit
@@ -3015,7 +3022,7 @@ CFGBlock *
CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
AddStmtChoice asc) {
findConstructionContexts(
- ConstructionContext::create(cfg->getBumpVectorContext(), MTE),
+ ConstructionContextLayer::create(cfg->getBumpVectorContext(), MTE),
MTE->getTemporary());
return VisitStmt(MTE, asc);
@@ -4002,7 +4009,7 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
appendStmt(Block, E);
findConstructionContexts(
- ConstructionContext::create(cfg->getBumpVectorContext(), E),
+ ConstructionContextLayer::create(cfg->getBumpVectorContext(), E),
E->getSubExpr());
// We do not want to propagate the AlwaysAdd property.
@@ -4025,7 +4032,7 @@ CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
appendStmt(Block, NE);
findConstructionContexts(
- ConstructionContext::create(cfg->getBumpVectorContext(), NE),
+ ConstructionContextLayer::create(cfg->getBumpVectorContext(), NE),
const_cast<CXXConstructExpr *>(NE->getConstructExpr()));
if (NE->getInitializer())
@@ -4752,19 +4759,44 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
} else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
OS << " (CXXConstructExpr, ";
if (Optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
- // TODO: Refactor into ConstructionContext::print().
- if (const Stmt *S = CE->getTriggerStmt())
- Helper.handledStmt(const_cast<Stmt *>(S), OS);
- else if (const CXXCtorInitializer *I = CE->getTriggerInit())
- print_initializer(OS, Helper, I);
- else
- llvm_unreachable("Unexpected trigger kind!");
- OS << ", ";
- if (const Stmt *S = CE->getMaterializedTemporary()) {
- if (S != CE->getTriggerStmt()) {
- Helper.handledStmt(const_cast<Stmt *>(S), OS);
- OS << ", ";
- }
+ const ConstructionContext *CC = CE->getConstructionContext();
+ const Stmt *S1 = nullptr, *S2 = nullptr;
+ switch (CC->getKind()) {
+ case ConstructionContext::ConstructorInitializerKind: {
+ const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
+ print_initializer(OS, Helper, ICC->getCXXCtorInitializer());
+ OS << ", ";
+ break;
+ }
+ case ConstructionContext::SimpleVariableKind: {
+ const auto *DSCC = cast<SimpleVariableConstructionContext>(CC);
+ S1 = DSCC->getDeclStmt();
+ break;
+ }
+ case ConstructionContext::NewAllocatedObjectKind: {
+ const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
+ S1 = NECC->getCXXNewExpr();
+ break;
+ }
+ case ConstructionContext::ReturnedValueKind: {
+ const auto *RSCC = cast<ReturnedValueConstructionContext>(CC);
+ S1 = RSCC->getReturnStmt();
+ break;
+ }
+ case ConstructionContext::TemporaryObjectKind: {
+ const auto *TOCC = cast<TemporaryObjectConstructionContext>(CC);
+ S1 = TOCC->getCXXBindTemporaryExpr();
+ S2 = TOCC->getMaterializedTemporaryExpr();
+ break;
+ }
+ }
+ if (S1) {
+ Helper.handledStmt(const_cast<Stmt *>(S1), OS);
+ OS << ", ";
+ }
+ if (S2) {
+ Helper.handledStmt(const_cast<Stmt *>(S2), OS);
+ OS << ", ";
}
}
OS << CCE->getType().getAsString() << ")";
diff --git a/clang/lib/Analysis/CMakeLists.txt b/clang/lib/Analysis/CMakeLists.txt
index fdc9e6cee8e..432067d9815 100644
--- a/clang/lib/Analysis/CMakeLists.txt
+++ b/clang/lib/Analysis/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_library(clangAnalysis
CallGraph.cpp
CloneDetection.cpp
CocoaConventions.cpp
+ ConstructionContext.cpp
Consumed.cpp
CodeInjector.cpp
Dominators.cpp
diff --git a/clang/lib/Analysis/ConstructionContext.cpp b/clang/lib/Analysis/ConstructionContext.cpp
new file mode 100644
index 00000000000..aea329b1fea
--- /dev/null
+++ b/clang/lib/Analysis/ConstructionContext.cpp
@@ -0,0 +1,92 @@
+//===- ConstructionContext.cpp - CFG constructor information --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ConstructionContext class and its sub-classes,
+// which represent various different ways of constructing C++ objects
+// with the additional information the users may want to know about
+// the constructor.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/ConstructionContext.h"
+
+using namespace clang;
+
+const ConstructionContextLayer *
+ConstructionContextLayer::create(BumpVectorContext &C, TriggerTy Trigger,
+ const ConstructionContextLayer *Parent) {
+ ConstructionContextLayer *CC =
+ C.getAllocator().Allocate<ConstructionContextLayer>();
+ return new (CC) ConstructionContextLayer(Trigger, Parent);
+}
+
+bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
+ const ConstructionContextLayer *Other) const {
+ const ConstructionContextLayer *Self = this;
+ while (true) {
+ if (!Other)
+ return Self;
+ if (!Self || !Self->isSameLayer(Other))
+ return false;
+ Self = Self->getParent();
+ Other = Other->getParent();
+ }
+ llvm_unreachable("The above loop can only be terminated via return!");
+}
+
+const ConstructionContext *ConstructionContext::createFromLayers(
+ BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
+ // Before this point all we've had was a stockpile of arbitrary layers.
+ // Now validate that it is shaped as one of the finite amount of expected
+ // patterns.
+ if (const Stmt *S = TopLayer->getTriggerStmt()) {
+ if (const auto *DS = dyn_cast<DeclStmt>(S)) {
+ assert(TopLayer->isLast());
+ auto *CC =
+ C.getAllocator().Allocate<SimpleVariableConstructionContext>();
+ return new (CC) SimpleVariableConstructionContext(DS);
+ } else if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
+ assert(TopLayer->isLast());
+ auto *CC =
+ C.getAllocator().Allocate<NewAllocatedObjectConstructionContext>();
+ return new (CC) NewAllocatedObjectConstructionContext(NE);
+ } else if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(S)) {
+ const MaterializeTemporaryExpr *MTE = nullptr;
+ assert(BTE->getType().getCanonicalType()
+ ->getAsCXXRecordDecl()->hasNonTrivialDestructor());
+ // For temporaries with destructors, there may or may not be
+ // lifetime extension on the parent layer.
+ if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) {
+ assert(ParentLayer->isLast());
+ MTE = cast<MaterializeTemporaryExpr>(ParentLayer->getTriggerStmt());
+ }
+ auto *CC =
+ C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
+ return new (CC) TemporaryObjectConstructionContext(BTE, MTE);
+ } else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
+ assert(MTE->getType().getCanonicalType()
+ ->getAsCXXRecordDecl()->hasTrivialDestructor());
+ assert(TopLayer->isLast());
+ auto *CC =
+ C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
+ return new (CC) TemporaryObjectConstructionContext(nullptr, MTE);
+ } else if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
+ assert(TopLayer->isLast());
+ auto *CC =
+ C.getAllocator().Allocate<ReturnedValueConstructionContext>();
+ return new (CC) ReturnedValueConstructionContext(RS);
+ }
+ } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
+ assert(TopLayer->isLast());
+ auto *CC =
+ C.getAllocator().Allocate<ConstructorInitializerConstructionContext>();
+ return new (CC) ConstructorInitializerConstructionContext(I);
+ }
+ llvm_unreachable("Unexpected construction context!");
+}
OpenPOWER on IntegriCloud