Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Analysis/ConstructionContext.cpp
35233 views
1
//===- ConstructionContext.cpp - CFG constructor information --------------===//
2
//
3
// 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
6
//
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"
17
#include "clang/AST/ExprObjC.h"
18
19
using namespace clang;
20
21
const ConstructionContextLayer *
22
ConstructionContextLayer::create(BumpVectorContext &C,
23
const ConstructionContextItem &Item,
24
const ConstructionContextLayer *Parent) {
25
ConstructionContextLayer *CC =
26
C.getAllocator().Allocate<ConstructionContextLayer>();
27
return new (CC) ConstructionContextLayer(Item, Parent);
28
}
29
30
bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
31
const ConstructionContextLayer *Other) const {
32
const ConstructionContextLayer *Self = this;
33
while (true) {
34
if (!Other)
35
return Self;
36
if (!Self || !(Self->Item == Other->Item))
37
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
44
const ConstructionContext *
45
ConstructionContext::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
95
const 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
case ConstructionContextItem::LambdaCaptureKind: {
160
assert(ParentLayer->isLast());
161
const auto *E = cast<LambdaExpr>(ParentItem.getStmt());
162
return create<LambdaCaptureConstructionContext>(C, E,
163
ParentItem.getIndex());
164
}
165
} // switch (ParentItem.getKind())
166
167
llvm_unreachable("Unexpected construction context with destructor!");
168
}
169
170
const ConstructionContext *ConstructionContext::createFromLayers(
171
BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
172
// Before this point all we've had was a stockpile of arbitrary layers.
173
// Now validate that it is shaped as one of the finite amount of expected
174
// patterns.
175
const ConstructionContextItem &TopItem = TopLayer->getItem();
176
switch (TopItem.getKind()) {
177
case ConstructionContextItem::VariableKind: {
178
assert(TopLayer->isLast());
179
const auto *DS = cast<DeclStmt>(TopItem.getStmt());
180
return create<SimpleVariableConstructionContext>(C, DS);
181
}
182
case ConstructionContextItem::NewAllocatorKind: {
183
assert(TopLayer->isLast());
184
const auto *NE = cast<CXXNewExpr>(TopItem.getStmt());
185
return create<NewAllocatedObjectConstructionContext>(C, NE);
186
}
187
case ConstructionContextItem::ReturnKind: {
188
assert(TopLayer->isLast());
189
const auto *RS = cast<ReturnStmt>(TopItem.getStmt());
190
return create<SimpleReturnedValueConstructionContext>(C, RS);
191
}
192
case ConstructionContextItem::MaterializationKind: {
193
const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt());
194
return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr,
195
TopLayer->getParent());
196
}
197
case ConstructionContextItem::TemporaryDestructorKind: {
198
const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt());
199
assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl()
200
->hasNonTrivialDestructor());
201
return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent());
202
}
203
case ConstructionContextItem::ElidedDestructorKind: {
204
llvm_unreachable("Elided destructor items are not produced by the CFG!");
205
}
206
case ConstructionContextItem::ElidableConstructorKind: {
207
llvm_unreachable("The argument needs to be materialized first!");
208
}
209
case ConstructionContextItem::LambdaCaptureKind: {
210
assert(TopLayer->isLast());
211
const auto *E = cast<LambdaExpr>(TopItem.getStmt());
212
return create<LambdaCaptureConstructionContext>(C, E, TopItem.getIndex());
213
}
214
case ConstructionContextItem::InitializerKind: {
215
assert(TopLayer->isLast());
216
const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
217
return create<SimpleConstructorInitializerConstructionContext>(C, I);
218
}
219
case ConstructionContextItem::ArgumentKind: {
220
assert(TopLayer->isLast());
221
const auto *E = cast<Expr>(TopItem.getStmt());
222
return create<ArgumentConstructionContext>(C, E, TopItem.getIndex(),
223
/*BTE=*/nullptr);
224
}
225
} // switch (TopItem.getKind())
226
llvm_unreachable("Unexpected construction context!");
227
}
228
229