1 //===- ConstructionContext.cpp - CFG constructor information --------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines the ConstructionContext class and its sub-classes,
11 // which represent various different ways of constructing C++ objects
12 // with the additional information the users may want to know about
15 //===----------------------------------------------------------------------===//
17 #include "clang/Analysis/ConstructionContext.h"
19 using namespace clang;
21 const ConstructionContextLayer *
22 ConstructionContextLayer::create(BumpVectorContext &C, TriggerTy Trigger,
23 const ConstructionContextLayer *Parent) {
24 ConstructionContextLayer *CC =
25 C.getAllocator().Allocate<ConstructionContextLayer>();
26 return new (CC) ConstructionContextLayer(Trigger, Parent);
29 bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
30 const ConstructionContextLayer *Other) const {
31 const ConstructionContextLayer *Self = this;
35 if (!Self || !Self->isSameLayer(Other))
37 Self = Self->getParent();
38 Other = Other->getParent();
40 llvm_unreachable("The above loop can only be terminated via return!");
43 const ConstructionContext *ConstructionContext::createFromLayers(
44 BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
45 // Before this point all we've had was a stockpile of arbitrary layers.
46 // Now validate that it is shaped as one of the finite amount of expected
48 if (const Stmt *S = TopLayer->getTriggerStmt()) {
49 if (const auto *DS = dyn_cast<DeclStmt>(S)) {
50 assert(TopLayer->isLast());
51 return create<SimpleVariableConstructionContext>(C, DS);
53 if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
54 assert(TopLayer->isLast());
55 return create<NewAllocatedObjectConstructionContext>(C, NE);
57 if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(S)) {
58 const MaterializeTemporaryExpr *MTE = nullptr;
59 assert(BTE->getType().getCanonicalType()
60 ->getAsCXXRecordDecl()->hasNonTrivialDestructor());
61 // For temporaries with destructors, there may or may not be
62 // lifetime extension on the parent layer.
63 if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) {
64 // C++17 *requires* elision of the constructor at the return site
65 // and at variable/member initialization site, while previous standards
66 // were allowing an optional elidable constructor.
67 // This is the C++17 copy-elided construction into a ctor initializer.
68 if (const CXXCtorInitializer *I = ParentLayer->getTriggerInit()) {
70 CXX17ElidedCopyConstructorInitializerConstructionContext>(C,
73 assert(ParentLayer->getTriggerStmt() &&
74 "Non-statement-based layers have been handled above!");
75 // This is the normal, non-C++17 case: a temporary object which has
76 // both destruction and materialization info attached to it in the AST.
77 if ((MTE = dyn_cast<MaterializeTemporaryExpr>(
78 ParentLayer->getTriggerStmt()))) {
79 if (MTE->getStorageDuration() != SD_FullExpression) {
80 // If the temporary is lifetime-extended, don't save the BTE,
81 // because we don't need a temporary destructor, but an automatic
86 // Handle pre-C++17 copy and move elision.
87 const CXXConstructExpr *ElidedCE = nullptr;
88 const ConstructionContext *ElidedCC = nullptr;
89 if (const ConstructionContextLayer *ElidedLayer =
90 ParentLayer->getParent()) {
91 ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt());
92 assert(ElidedCE->isElidable());
93 // We're creating a construction context that might have already
94 // been created elsewhere. Maybe we should unique our construction
95 // contexts. That's what we often do, but in this case it's unlikely
96 // to bring any benefits.
97 ElidedCC = createFromLayers(C, ElidedLayer->getParent());
99 // We may fail to create the elided construction context.
100 // In this case, skip copy elision entirely.
101 return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
104 return create<ElidedTemporaryObjectConstructionContext>(
105 C, BTE, MTE, ElidedCE, ElidedCC);
108 assert(ParentLayer->isLast());
109 return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
111 assert(ParentLayer->isLast());
113 // This is a constructor into a function argument. Not implemented yet.
114 if (isa<CallExpr>(ParentLayer->getTriggerStmt()))
116 // This is C++17 copy-elided construction into return statement.
117 if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
118 assert(!RS->getRetValue()->getType().getCanonicalType()
119 ->getAsCXXRecordDecl()->hasTrivialDestructor());
120 return create<CXX17ElidedCopyReturnedValueConstructionContext>(C,
123 // This is C++17 copy-elided construction into a simple variable.
124 if (auto *DS = dyn_cast<DeclStmt>(ParentLayer->getTriggerStmt())) {
125 assert(!cast<VarDecl>(DS->getSingleDecl())->getType()
126 .getCanonicalType()->getAsCXXRecordDecl()
127 ->hasTrivialDestructor());
128 return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE);
130 llvm_unreachable("Unexpected construction context with destructor!");
132 // A temporary object that doesn't require materialization.
133 // In particular, it shouldn't require copy elision, because
134 // copy/move constructors take a reference, which requires
135 // materialization to obtain the glvalue.
136 return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
139 if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
140 // If the object requires destruction and is not lifetime-extended,
141 // then it must have a BTE within its MTE.
142 // FIXME: This should be an assertion.
143 if (!(MTE->getType().getCanonicalType()
144 ->getAsCXXRecordDecl()->hasTrivialDestructor() ||
145 MTE->getStorageDuration() != SD_FullExpression))
148 // Handle pre-C++17 copy and move elision.
149 const CXXConstructExpr *ElidedCE = nullptr;
150 const ConstructionContext *ElidedCC = nullptr;
151 if (const ConstructionContextLayer *ElidedLayer = TopLayer->getParent()) {
152 ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt());
153 assert(ElidedCE->isElidable());
154 // We're creating a construction context that might have already
155 // been created elsewhere. Maybe we should unique our construction
156 // contexts. That's what we often do, but in this case it's unlikely
157 // to bring any benefits.
158 ElidedCC = createFromLayers(C, ElidedLayer->getParent());
160 // We may fail to create the elided construction context.
161 // In this case, skip copy elision entirely.
162 return create<SimpleTemporaryObjectConstructionContext>(C, nullptr,
165 return create<ElidedTemporaryObjectConstructionContext>(
166 C, nullptr, MTE, ElidedCE, ElidedCC);
168 assert(TopLayer->isLast());
169 return create<SimpleTemporaryObjectConstructionContext>(C, nullptr, MTE);
171 if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
172 assert(TopLayer->isLast());
173 return create<SimpleReturnedValueConstructionContext>(C, RS);
175 // This is a constructor into a function argument. Not implemented yet.
176 if (isa<CallExpr>(TopLayer->getTriggerStmt()))
178 llvm_unreachable("Unexpected construction context with statement!");
179 } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
180 assert(TopLayer->isLast());
181 return create<SimpleConstructorInitializerConstructionContext>(C, I);
183 llvm_unreachable("Unexpected construction context!");