clang  19.0.0git
ConstructionContext.cpp
Go to the documentation of this file.
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 
17 #include "clang/AST/ExprObjC.h"
18 
19 using namespace clang;
20 
23  const ConstructionContextItem &Item,
26  C.getAllocator().Allocate<ConstructionContextLayer>();
27  return new (CC) ConstructionContextLayer(Item, Parent);
28 }
29 
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(
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()
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() ==
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(
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()) {
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  }
116  llvm_unreachable("This context does not accept a bound temporary!");
117  }
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 
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  }
134  llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!");
135  }
137  llvm_unreachable("Elided destructor items are not produced by the CFG!");
138  }
140  llvm_unreachable("Materialization is necessary to put temporary into a "
141  "copy or move constructor!");
142  }
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  }
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  }
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 
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()) {
178  assert(TopLayer->isLast());
179  const auto *DS = cast<DeclStmt>(TopItem.getStmt());
180  return create<SimpleVariableConstructionContext>(C, DS);
181  }
183  assert(TopLayer->isLast());
184  const auto *NE = cast<CXXNewExpr>(TopItem.getStmt());
185  return create<NewAllocatedObjectConstructionContext>(C, NE);
186  }
188  assert(TopLayer->isLast());
189  const auto *RS = cast<ReturnStmt>(TopItem.getStmt());
190  return create<SimpleReturnedValueConstructionContext>(C, RS);
191  }
193  const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt());
194  return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr,
195  TopLayer->getParent());
196  }
198  const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt());
199  assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl()
201  return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent());
202  }
204  llvm_unreachable("Elided destructor items are not produced by the CFG!");
205  }
207  llvm_unreachable("The argument needs to be materialized first!");
208  }
210  assert(TopLayer->isLast());
211  const auto *E = cast<LambdaExpr>(TopItem.getStmt());
212  return create<LambdaCaptureConstructionContext>(C, E, TopItem.getIndex());
213  }
215  assert(TopLayer->isLast());
216  const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
217  return create<SimpleConstructorInitializerConstructionContext>(C, I);
218  }
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 }
NodeId Parent
Definition: ASTDiff.cpp:191
Represents binding an expression to a temporary.
Definition: ExprCXX.h:1487
Represents a call to a C++ constructor.
Definition: ExprCXX.h:1542
bool isElidable() const
Whether this construction is elidable.
Definition: ExprCXX.h:1611
Represents a C++ base or member initializer.
Definition: DeclCXX.h:2300
bool hasTrivialDestructor() const
Determine whether this class has a trivial destructor (C++ [class.dtor]p3)
Definition: DeclCXX.h:1367
bool hasNonTrivialDestructor() const
Determine whether this class has a non-trivial destructor (C++ [class.dtor]p3)
Definition: DeclCXX.h:1377
Represents a single point (AST node) in the program that requires attention during construction of an...
const CXXCtorInitializer * getCXXCtorInitializer() const
The construction site is not necessarily a statement.
unsigned getIndex() const
If a single trigger statement triggers multiple constructors, they are usually being enumerated.
const Stmt * getStmt() const
The construction site - the statement that triggered the construction for one of its parts.
Construction context can be seen as a linked list of multiple layers.
static const ConstructionContextLayer * create(BumpVectorContext &C, const ConstructionContextItem &Item, const ConstructionContextLayer *Parent=nullptr)
bool isStrictlyMoreSpecificThan(const ConstructionContextLayer *Other) const
See if Other is a proper initial segment of this construction context in terms of the parent chain - ...
const ConstructionContextItem & getItem() const
const ConstructionContextLayer * getParent() const
ConstructionContext's subclasses describe different ways of constructing an object in C++.
static const ConstructionContext * createFromLayers(BumpVectorContext &C, const ConstructionContextLayer *TopLayer)
Consume the construction context layer, together with its parent layers, and wrap it up into a comple...
QualType getType() const
Definition: Expr.h:142
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition: ExprCXX.h:4721
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Definition: ExprCXX.h:4746
QualType getCanonicalType() const
Definition: Type.h:7423
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1881
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:869
The JSON file list parser is used to communicate input to InstallAPI.
@ SD_FullExpression
Full-expression storage duration (for temporaries).
Definition: Specifiers.h:325
@ Other
Other implicit parameter.