blob: 6ba1e2173d2cc383c9eaa094389e5331c5a1fd6d [file] [log] [blame]
Artem Dergachev40684812018-02-27 20:03:35 +00001//===- ConstructionContext.cpp - CFG constructor information --------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Artem Dergachev40684812018-02-27 20:03:35 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the ConstructionContext class and its sub-classes,
10// which represent various different ways of constructing C++ objects
11// with the additional information the users may want to know about
12// the constructor.
13//
14//===----------------------------------------------------------------------===//
15
16#include "clang/Analysis/ConstructionContext.h"
Artem Dergachevbd880fe2018-07-31 19:39:37 +000017#include "clang/AST/ExprObjC.h"
Artem Dergachev40684812018-02-27 20:03:35 +000018
19using namespace clang;
20
21const ConstructionContextLayer *
Artem Dergachev1f8cb3a2018-07-31 21:12:42 +000022ConstructionContextLayer::create(BumpVectorContext &C,
23 const ConstructionContextItem &Item,
Artem Dergachev40684812018-02-27 20:03:35 +000024 const ConstructionContextLayer *Parent) {
25 ConstructionContextLayer *CC =
26 C.getAllocator().Allocate<ConstructionContextLayer>();
Artem Dergachev1f8cb3a2018-07-31 21:12:42 +000027 return new (CC) ConstructionContextLayer(Item, Parent);
Artem Dergachev40684812018-02-27 20:03:35 +000028}
29
30bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
31 const ConstructionContextLayer *Other) const {
32 const ConstructionContextLayer *Self = this;
33 while (true) {
34 if (!Other)
35 return Self;
Artem Dergachev1f8cb3a2018-07-31 21:12:42 +000036 if (!Self || !(Self->Item == Other->Item))
Artem Dergachev40684812018-02-27 20:03:35 +000037 return false;
38 Self = Self->getParent();
39 Other = Other->getParent();
40 }
41 llvm_unreachable("The above loop can only be terminated via return!");
42}
43
Artem Dergachev1f8cb3a2018-07-31 21:12:42 +000044const ConstructionContext *
45ConstructionContext::createMaterializedTemporaryFromLayers(
46 BumpVectorContext &C, const MaterializeTemporaryExpr *MTE,
47 const CXXBindTemporaryExpr *BTE,
48 const ConstructionContextLayer *ParentLayer) {
49 assert(MTE);
50
51 // If the object requires destruction and is not lifetime-extended,
52 // then it must have a BTE within its MTE, otherwise it shouldn't.
53 // FIXME: This should be an assertion.
54 if (!BTE && !(MTE->getType().getCanonicalType()->getAsCXXRecordDecl()
55 ->hasTrivialDestructor() ||
56 MTE->getStorageDuration() != SD_FullExpression)) {
57 return nullptr;
58 }
59
60 // If the temporary is lifetime-extended, don't save the BTE,
61 // because we don't need a temporary destructor, but an automatic
62 // destructor.
63 if (MTE->getStorageDuration() != SD_FullExpression) {
64 BTE = nullptr;
65 }
66
67 // Handle pre-C++17 copy and move elision.
68 const CXXConstructExpr *ElidedCE = nullptr;
69 const ConstructionContext *ElidedCC = nullptr;
70 if (ParentLayer) {
71 const ConstructionContextItem &ElidedItem = ParentLayer->getItem();
72 assert(ElidedItem.getKind() ==
73 ConstructionContextItem::ElidableConstructorKind);
74 ElidedCE = cast<CXXConstructExpr>(ElidedItem.getStmt());
75 assert(ElidedCE->isElidable());
76 // We're creating a construction context that might have already
77 // been created elsewhere. Maybe we should unique our construction
78 // contexts. That's what we often do, but in this case it's unlikely
79 // to bring any benefits.
80 ElidedCC = createFromLayers(C, ParentLayer->getParent());
81 if (!ElidedCC) {
82 // We may fail to create the elided construction context.
83 // In this case, skip copy elision entirely.
84 return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
85 }
86 return create<ElidedTemporaryObjectConstructionContext>(
87 C, BTE, MTE, ElidedCE, ElidedCC);
88 }
89
90 // This is a normal temporary.
91 assert(!ParentLayer);
92 return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
93}
94
95const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers(
96 BumpVectorContext &C, const CXXBindTemporaryExpr *BTE,
97 const ConstructionContextLayer *ParentLayer) {
98 if (!ParentLayer) {
99 // A temporary object that doesn't require materialization.
100 // In particular, it shouldn't require copy elision, because
101 // copy/move constructors take a reference, which requires
102 // materialization to obtain the glvalue.
103 return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
104 /*MTE=*/nullptr);
105 }
106
107 const ConstructionContextItem &ParentItem = ParentLayer->getItem();
108 switch (ParentItem.getKind()) {
109 case ConstructionContextItem::VariableKind: {
110 const auto *DS = cast<DeclStmt>(ParentItem.getStmt());
111 assert(!cast<VarDecl>(DS->getSingleDecl())->getType().getCanonicalType()
112 ->getAsCXXRecordDecl()->hasTrivialDestructor());
113 return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE);
114 }
115 case ConstructionContextItem::NewAllocatorKind: {
116 llvm_unreachable("This context does not accept a bound temporary!");
117 }
118 case ConstructionContextItem::ReturnKind: {
119 assert(ParentLayer->isLast());
120 const auto *RS = cast<ReturnStmt>(ParentItem.getStmt());
121 assert(!RS->getRetValue()->getType().getCanonicalType()
122 ->getAsCXXRecordDecl()->hasTrivialDestructor());
123 return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, RS,
124 BTE);
125 }
126
127 case ConstructionContextItem::MaterializationKind: {
128 // No assert. We may have an elidable copy on the grandparent layer.
129 const auto *MTE = cast<MaterializeTemporaryExpr>(ParentItem.getStmt());
130 return createMaterializedTemporaryFromLayers(C, MTE, BTE,
131 ParentLayer->getParent());
132 }
133 case ConstructionContextItem::TemporaryDestructorKind: {
134 llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!");
135 }
136 case ConstructionContextItem::ElidedDestructorKind: {
137 llvm_unreachable("Elided destructor items are not produced by the CFG!");
138 }
139 case ConstructionContextItem::ElidableConstructorKind: {
140 llvm_unreachable("Materialization is necessary to put temporary into a "
141 "copy or move constructor!");
142 }
143 case ConstructionContextItem::ArgumentKind: {
144 assert(ParentLayer->isLast());
145 const auto *E = cast<Expr>(ParentItem.getStmt());
146 assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) ||
147 isa<ObjCMessageExpr>(E));
148 return create<ArgumentConstructionContext>(C, E, ParentItem.getIndex(),
149 BTE);
150 }
151 case ConstructionContextItem::InitializerKind: {
152 assert(ParentLayer->isLast());
153 const auto *I = ParentItem.getCXXCtorInitializer();
154 assert(!I->getAnyMember()->getType().getCanonicalType()
155 ->getAsCXXRecordDecl()->hasTrivialDestructor());
156 return create<CXX17ElidedCopyConstructorInitializerConstructionContext>(
157 C, I, BTE);
158 }
159 } // switch (ParentItem.getKind())
160
161 llvm_unreachable("Unexpected construction context with destructor!");
162}
163
Artem Dergachev40684812018-02-27 20:03:35 +0000164const ConstructionContext *ConstructionContext::createFromLayers(
165 BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
166 // Before this point all we've had was a stockpile of arbitrary layers.
167 // Now validate that it is shaped as one of the finite amount of expected
168 // patterns.
Artem Dergachev1f8cb3a2018-07-31 21:12:42 +0000169 const ConstructionContextItem &TopItem = TopLayer->getItem();
170 switch (TopItem.getKind()) {
171 case ConstructionContextItem::VariableKind: {
Artem Dergachev40684812018-02-27 20:03:35 +0000172 assert(TopLayer->isLast());
Artem Dergachev1f8cb3a2018-07-31 21:12:42 +0000173 const auto *DS = cast<DeclStmt>(TopItem.getStmt());
174 return create<SimpleVariableConstructionContext>(C, DS);
175 }
176 case ConstructionContextItem::NewAllocatorKind: {
177 assert(TopLayer->isLast());
178 const auto *NE = cast<CXXNewExpr>(TopItem.getStmt());
179 return create<NewAllocatedObjectConstructionContext>(C, NE);
180 }
181 case ConstructionContextItem::ReturnKind: {
182 assert(TopLayer->isLast());
183 const auto *RS = cast<ReturnStmt>(TopItem.getStmt());
184 return create<SimpleReturnedValueConstructionContext>(C, RS);
185 }
186 case ConstructionContextItem::MaterializationKind: {
187 const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt());
188 return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr,
189 TopLayer->getParent());
190 }
191 case ConstructionContextItem::TemporaryDestructorKind: {
192 const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt());
193 assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl()
194 ->hasNonTrivialDestructor());
195 return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent());
196 }
197 case ConstructionContextItem::ElidedDestructorKind: {
198 llvm_unreachable("Elided destructor items are not produced by the CFG!");
199 }
200 case ConstructionContextItem::ElidableConstructorKind: {
201 llvm_unreachable("The argument needs to be materialized first!");
202 }
203 case ConstructionContextItem::InitializerKind: {
204 assert(TopLayer->isLast());
205 const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
Artem Dergachev922455f2018-03-22 22:02:38 +0000206 return create<SimpleConstructorInitializerConstructionContext>(C, I);
Artem Dergachev40684812018-02-27 20:03:35 +0000207 }
Artem Dergachev1f8cb3a2018-07-31 21:12:42 +0000208 case ConstructionContextItem::ArgumentKind: {
209 assert(TopLayer->isLast());
210 const auto *E = cast<Expr>(TopItem.getStmt());
211 return create<ArgumentConstructionContext>(C, E, TopItem.getIndex(),
212 /*BTE=*/nullptr);
213 }
214 } // switch (TopItem.getKind())
Artem Dergachev40684812018-02-27 20:03:35 +0000215 llvm_unreachable("Unexpected construction context!");
216}