annotate clang/lib/Analysis/ConstructionContext.cpp @ 222:81f6424ef0e3 llvm-original

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