summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis/ConstructionContext.cpp
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-07-31 21:12:42 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-07-31 21:12:42 +0000
commit1f8cb3a65ee7c8ace65801bbbe34cc9abd10f0ec (patch)
tree67f02aca411a0a901dd9eb838242fe737d248065 /clang/lib/Analysis/ConstructionContext.cpp
parent559cc6978964e20ed7cd1e999419cb3b225e1f49 (diff)
downloadbcm5719-llvm-1f8cb3a65ee7c8ace65801bbbe34cc9abd10f0ec.tar.gz
bcm5719-llvm-1f8cb3a65ee7c8ace65801bbbe34cc9abd10f0ec.zip
[CFG] [analyzer] NFC: Enumerate construction context layer kinds.
This is a refactoring patch; no functional change intended. The common part of ConstructionContextLayer and ConstructedObjectKey is factored out into a new structure, ConstructionContextItem. Various sub-kinds of ConstructionContextItem are enumerated in order to provide richer information about construction contexts. Differential Revision: https://reviews.llvm.org/D49210. llvm-svn: 338439
Diffstat (limited to 'clang/lib/Analysis/ConstructionContext.cpp')
-rw-r--r--clang/lib/Analysis/ConstructionContext.cpp314
1 files changed, 167 insertions, 147 deletions
diff --git a/clang/lib/Analysis/ConstructionContext.cpp b/clang/lib/Analysis/ConstructionContext.cpp
index 9d255a0bcfa..8169d4a93a6 100644
--- a/clang/lib/Analysis/ConstructionContext.cpp
+++ b/clang/lib/Analysis/ConstructionContext.cpp
@@ -20,12 +20,12 @@
using namespace clang;
const ConstructionContextLayer *
-ConstructionContextLayer::create(BumpVectorContext &C, TriggerTy Trigger,
- unsigned Index,
+ConstructionContextLayer::create(BumpVectorContext &C,
+ const ConstructionContextItem &Item,
const ConstructionContextLayer *Parent) {
ConstructionContextLayer *CC =
C.getAllocator().Allocate<ConstructionContextLayer>();
- return new (CC) ConstructionContextLayer(Trigger, Index, Parent);
+ return new (CC) ConstructionContextLayer(Item, Parent);
}
bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
@@ -34,7 +34,7 @@ bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
while (true) {
if (!Other)
return Self;
- if (!Self || !Self->isSameLayer(Other))
+ if (!Self || !(Self->Item == Other->Item))
return false;
Self = Self->getParent();
Other = Other->getParent();
@@ -42,156 +42,176 @@ bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
llvm_unreachable("The above loop can only be terminated via return!");
}
+const ConstructionContext *
+ConstructionContext::createMaterializedTemporaryFromLayers(
+ BumpVectorContext &C, const MaterializeTemporaryExpr *MTE,
+ const CXXBindTemporaryExpr *BTE,
+ const ConstructionContextLayer *ParentLayer) {
+ assert(MTE);
+
+ // If the object requires destruction and is not lifetime-extended,
+ // then it must have a BTE within its MTE, otherwise it shouldn't.
+ // FIXME: This should be an assertion.
+ if (!BTE && !(MTE->getType().getCanonicalType()->getAsCXXRecordDecl()
+ ->hasTrivialDestructor() ||
+ MTE->getStorageDuration() != SD_FullExpression)) {
+ return nullptr;
+ }
+
+ // If the temporary is lifetime-extended, don't save the BTE,
+ // because we don't need a temporary destructor, but an automatic
+ // destructor.
+ if (MTE->getStorageDuration() != SD_FullExpression) {
+ BTE = nullptr;
+ }
+
+ // Handle pre-C++17 copy and move elision.
+ const CXXConstructExpr *ElidedCE = nullptr;
+ const ConstructionContext *ElidedCC = nullptr;
+ if (ParentLayer) {
+ const ConstructionContextItem &ElidedItem = ParentLayer->getItem();
+ assert(ElidedItem.getKind() ==
+ ConstructionContextItem::ElidableConstructorKind);
+ ElidedCE = cast<CXXConstructExpr>(ElidedItem.getStmt());
+ assert(ElidedCE->isElidable());
+ // We're creating a construction context that might have already
+ // been created elsewhere. Maybe we should unique our construction
+ // contexts. That's what we often do, but in this case it's unlikely
+ // to bring any benefits.
+ ElidedCC = createFromLayers(C, ParentLayer->getParent());
+ if (!ElidedCC) {
+ // We may fail to create the elided construction context.
+ // In this case, skip copy elision entirely.
+ return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
+ }
+ return create<ElidedTemporaryObjectConstructionContext>(
+ C, BTE, MTE, ElidedCE, ElidedCC);
+ }
+
+ // This is a normal temporary.
+ assert(!ParentLayer);
+ return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
+}
+
+const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers(
+ BumpVectorContext &C, const CXXBindTemporaryExpr *BTE,
+ const ConstructionContextLayer *ParentLayer) {
+ if (!ParentLayer) {
+ // A temporary object that doesn't require materialization.
+ // In particular, it shouldn't require copy elision, because
+ // copy/move constructors take a reference, which requires
+ // materialization to obtain the glvalue.
+ return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
+ /*MTE=*/nullptr);
+ }
+
+ const ConstructionContextItem &ParentItem = ParentLayer->getItem();
+ switch (ParentItem.getKind()) {
+ case ConstructionContextItem::VariableKind: {
+ const auto *DS = cast<DeclStmt>(ParentItem.getStmt());
+ assert(!cast<VarDecl>(DS->getSingleDecl())->getType().getCanonicalType()
+ ->getAsCXXRecordDecl()->hasTrivialDestructor());
+ return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE);
+ }
+ case ConstructionContextItem::NewAllocatorKind: {
+ llvm_unreachable("This context does not accept a bound temporary!");
+ }
+ case ConstructionContextItem::ReturnKind: {
+ assert(ParentLayer->isLast());
+ const auto *RS = cast<ReturnStmt>(ParentItem.getStmt());
+ assert(!RS->getRetValue()->getType().getCanonicalType()
+ ->getAsCXXRecordDecl()->hasTrivialDestructor());
+ return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, RS,
+ BTE);
+ }
+
+ case ConstructionContextItem::MaterializationKind: {
+ // No assert. We may have an elidable copy on the grandparent layer.
+ const auto *MTE = cast<MaterializeTemporaryExpr>(ParentItem.getStmt());
+ return createMaterializedTemporaryFromLayers(C, MTE, BTE,
+ ParentLayer->getParent());
+ }
+ case ConstructionContextItem::TemporaryDestructorKind: {
+ llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!");
+ }
+ case ConstructionContextItem::ElidedDestructorKind: {
+ llvm_unreachable("Elided destructor items are not produced by the CFG!");
+ }
+ case ConstructionContextItem::ElidableConstructorKind: {
+ llvm_unreachable("Materialization is necessary to put temporary into a "
+ "copy or move constructor!");
+ }
+ case ConstructionContextItem::ArgumentKind: {
+ assert(ParentLayer->isLast());
+ const auto *E = cast<Expr>(ParentItem.getStmt());
+ assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) ||
+ isa<ObjCMessageExpr>(E));
+ return create<ArgumentConstructionContext>(C, E, ParentItem.getIndex(),
+ BTE);
+ }
+ case ConstructionContextItem::InitializerKind: {
+ assert(ParentLayer->isLast());
+ const auto *I = ParentItem.getCXXCtorInitializer();
+ assert(!I->getAnyMember()->getType().getCanonicalType()
+ ->getAsCXXRecordDecl()->hasTrivialDestructor());
+ return create<CXX17ElidedCopyConstructorInitializerConstructionContext>(
+ C, I, BTE);
+ }
+ } // switch (ParentItem.getKind())
+
+ llvm_unreachable("Unexpected construction context with destructor!");
+}
+
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());
- return create<SimpleVariableConstructionContext>(C, DS);
- }
- if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
- assert(TopLayer->isLast());
- return create<NewAllocatedObjectConstructionContext>(C, NE);
- }
- 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()) {
- // C++17 *requires* elision of the constructor at the return site
- // and at variable/member initialization site, while previous standards
- // were allowing an optional elidable constructor.
- // This is the C++17 copy-elided construction into a ctor initializer.
- if (const CXXCtorInitializer *I = ParentLayer->getTriggerInit()) {
- return create<
- CXX17ElidedCopyConstructorInitializerConstructionContext>(C,
- I, BTE);
- }
- assert(ParentLayer->getTriggerStmt() &&
- "Non-statement-based layers have been handled above!");
- // This is the normal, non-C++17 case: a temporary object which has
- // both destruction and materialization info attached to it in the AST.
- if ((MTE = dyn_cast<MaterializeTemporaryExpr>(
- ParentLayer->getTriggerStmt()))) {
- if (MTE->getStorageDuration() != SD_FullExpression) {
- // If the temporary is lifetime-extended, don't save the BTE,
- // because we don't need a temporary destructor, but an automatic
- // destructor.
- BTE = nullptr;
- }
-
- // Handle pre-C++17 copy and move elision.
- const CXXConstructExpr *ElidedCE = nullptr;
- const ConstructionContext *ElidedCC = nullptr;
- if (const ConstructionContextLayer *ElidedLayer =
- ParentLayer->getParent()) {
- ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt());
- assert(ElidedCE->isElidable());
- // We're creating a construction context that might have already
- // been created elsewhere. Maybe we should unique our construction
- // contexts. That's what we often do, but in this case it's unlikely
- // to bring any benefits.
- ElidedCC = createFromLayers(C, ElidedLayer->getParent());
- if (!ElidedCC) {
- // We may fail to create the elided construction context.
- // In this case, skip copy elision entirely.
- return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
- MTE);
- } else {
- return create<ElidedTemporaryObjectConstructionContext>(
- C, BTE, MTE, ElidedCE, ElidedCC);
- }
- }
- assert(ParentLayer->isLast());
- return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
- }
- assert(ParentLayer->isLast());
-
- // This is a constructor into a function argument.
- if (isa<CallExpr>(ParentLayer->getTriggerStmt()) ||
- isa<CXXConstructExpr>(ParentLayer->getTriggerStmt()) ||
- isa<ObjCMessageExpr>(ParentLayer->getTriggerStmt())) {
- return create<ArgumentConstructionContext>(
- C, cast<Expr>(ParentLayer->getTriggerStmt()),
- ParentLayer->getIndex(), BTE);
- }
- // This is C++17 copy-elided construction into return statement.
- if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
- assert(!RS->getRetValue()->getType().getCanonicalType()
- ->getAsCXXRecordDecl()->hasTrivialDestructor());
- return create<CXX17ElidedCopyReturnedValueConstructionContext>(C,
- RS, BTE);
- }
- // This is C++17 copy-elided construction into a simple variable.
- if (auto *DS = dyn_cast<DeclStmt>(ParentLayer->getTriggerStmt())) {
- assert(!cast<VarDecl>(DS->getSingleDecl())->getType()
- .getCanonicalType()->getAsCXXRecordDecl()
- ->hasTrivialDestructor());
- return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE);
- }
- llvm_unreachable("Unexpected construction context with destructor!");
- }
- // A temporary object that doesn't require materialization.
- // In particular, it shouldn't require copy elision, because
- // copy/move constructors take a reference, which requires
- // materialization to obtain the glvalue.
- return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
- /*MTE=*/nullptr);
- }
- if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
- // If the object requires destruction and is not lifetime-extended,
- // then it must have a BTE within its MTE.
- // FIXME: This should be an assertion.
- if (!(MTE->getType().getCanonicalType()
- ->getAsCXXRecordDecl()->hasTrivialDestructor() ||
- MTE->getStorageDuration() != SD_FullExpression))
- return nullptr;
-
- // Handle pre-C++17 copy and move elision.
- const CXXConstructExpr *ElidedCE = nullptr;
- const ConstructionContext *ElidedCC = nullptr;
- if (const ConstructionContextLayer *ElidedLayer = TopLayer->getParent()) {
- ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt());
- assert(ElidedCE->isElidable());
- // We're creating a construction context that might have already
- // been created elsewhere. Maybe we should unique our construction
- // contexts. That's what we often do, but in this case it's unlikely
- // to bring any benefits.
- ElidedCC = createFromLayers(C, ElidedLayer->getParent());
- if (!ElidedCC) {
- // We may fail to create the elided construction context.
- // In this case, skip copy elision entirely.
- return create<SimpleTemporaryObjectConstructionContext>(C, nullptr,
- MTE);
- }
- return create<ElidedTemporaryObjectConstructionContext>(
- C, nullptr, MTE, ElidedCE, ElidedCC);
- }
- assert(TopLayer->isLast());
- return create<SimpleTemporaryObjectConstructionContext>(C, nullptr, MTE);
- }
- if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
- assert(TopLayer->isLast());
- return create<SimpleReturnedValueConstructionContext>(C, RS);
- }
- // This is a constructor into a function argument.
- if (isa<CallExpr>(TopLayer->getTriggerStmt()) ||
- isa<CXXConstructExpr>(TopLayer->getTriggerStmt()) ||
- isa<ObjCMessageExpr>(TopLayer->getTriggerStmt())) {
- assert(TopLayer->isLast());
- return create<ArgumentConstructionContext>(
- C, cast<Expr>(TopLayer->getTriggerStmt()), TopLayer->getIndex(),
- /*BTE=*/nullptr);
- }
- llvm_unreachable("Unexpected construction context with statement!");
- } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
+ const ConstructionContextItem &TopItem = TopLayer->getItem();
+ switch (TopItem.getKind()) {
+ case ConstructionContextItem::VariableKind: {
assert(TopLayer->isLast());
+ const auto *DS = cast<DeclStmt>(TopItem.getStmt());
+ return create<SimpleVariableConstructionContext>(C, DS);
+ }
+ case ConstructionContextItem::NewAllocatorKind: {
+ assert(TopLayer->isLast());
+ const auto *NE = cast<CXXNewExpr>(TopItem.getStmt());
+ return create<NewAllocatedObjectConstructionContext>(C, NE);
+ }
+ case ConstructionContextItem::ReturnKind: {
+ assert(TopLayer->isLast());
+ const auto *RS = cast<ReturnStmt>(TopItem.getStmt());
+ return create<SimpleReturnedValueConstructionContext>(C, RS);
+ }
+ case ConstructionContextItem::MaterializationKind: {
+ const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt());
+ return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr,
+ TopLayer->getParent());
+ }
+ case ConstructionContextItem::TemporaryDestructorKind: {
+ const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt());
+ assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl()
+ ->hasNonTrivialDestructor());
+ return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent());
+ }
+ case ConstructionContextItem::ElidedDestructorKind: {
+ llvm_unreachable("Elided destructor items are not produced by the CFG!");
+ }
+ case ConstructionContextItem::ElidableConstructorKind: {
+ llvm_unreachable("The argument needs to be materialized first!");
+ }
+ case ConstructionContextItem::InitializerKind: {
+ assert(TopLayer->isLast());
+ const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
return create<SimpleConstructorInitializerConstructionContext>(C, I);
}
+ case ConstructionContextItem::ArgumentKind: {
+ assert(TopLayer->isLast());
+ const auto *E = cast<Expr>(TopItem.getStmt());
+ return create<ArgumentConstructionContext>(C, E, TopItem.getIndex(),
+ /*BTE=*/nullptr);
+ }
+ } // switch (TopItem.getKind())
llvm_unreachable("Unexpected construction context!");
}
OpenPOWER on IntegriCloud