clang  8.0.0svn
ConstructionContext.cpp
Go to the documentation of this file.
1 //===- ConstructionContext.cpp - CFG constructor information --------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
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
13 // the constructor.
14 //
15 //===----------------------------------------------------------------------===//
16 
18 #include "clang/AST/ExprObjC.h"
19 
20 using namespace clang;
21 
24  const ConstructionContextItem &Item,
27  C.getAllocator().Allocate<ConstructionContextLayer>();
28  return new (CC) ConstructionContextLayer(Item, Parent);
29 }
30 
32  const ConstructionContextLayer *Other) const {
33  const ConstructionContextLayer *Self = this;
34  while (true) {
35  if (!Other)
36  return Self;
37  if (!Self || !(Self->Item == Other->Item))
38  return false;
39  Self = Self->getParent();
40  Other = Other->getParent();
41  }
42  llvm_unreachable("The above loop can only be terminated via return!");
43 }
44 
45 const ConstructionContext *
46 ConstructionContext::createMaterializedTemporaryFromLayers(
48  const CXXBindTemporaryExpr *BTE,
49  const ConstructionContextLayer *ParentLayer) {
50  assert(MTE);
51 
52  // If the object requires destruction and is not lifetime-extended,
53  // then it must have a BTE within its MTE, otherwise it shouldn't.
54  // FIXME: This should be an assertion.
55  if (!BTE && !(MTE->getType().getCanonicalType()->getAsCXXRecordDecl()
58  return nullptr;
59  }
60 
61  // If the temporary is lifetime-extended, don't save the BTE,
62  // because we don't need a temporary destructor, but an automatic
63  // destructor.
64  if (MTE->getStorageDuration() != SD_FullExpression) {
65  BTE = nullptr;
66  }
67 
68  // Handle pre-C++17 copy and move elision.
69  const CXXConstructExpr *ElidedCE = nullptr;
70  const ConstructionContext *ElidedCC = nullptr;
71  if (ParentLayer) {
72  const ConstructionContextItem &ElidedItem = ParentLayer->getItem();
73  assert(ElidedItem.getKind() ==
75  ElidedCE = cast<CXXConstructExpr>(ElidedItem.getStmt());
76  assert(ElidedCE->isElidable());
77  // We're creating a construction context that might have already
78  // been created elsewhere. Maybe we should unique our construction
79  // contexts. That's what we often do, but in this case it's unlikely
80  // to bring any benefits.
81  ElidedCC = createFromLayers(C, ParentLayer->getParent());
82  if (!ElidedCC) {
83  // We may fail to create the elided construction context.
84  // In this case, skip copy elision entirely.
85  return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
86  }
87  return create<ElidedTemporaryObjectConstructionContext>(
88  C, BTE, MTE, ElidedCE, ElidedCC);
89  }
90 
91  // This is a normal temporary.
92  assert(!ParentLayer);
93  return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
94 }
95 
96 const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers(
98  const ConstructionContextLayer *ParentLayer) {
99  if (!ParentLayer) {
100  // A temporary object that doesn't require materialization.
101  // In particular, it shouldn't require copy elision, because
102  // copy/move constructors take a reference, which requires
103  // materialization to obtain the glvalue.
104  return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
105  /*MTE=*/nullptr);
106  }
107 
108  const ConstructionContextItem &ParentItem = ParentLayer->getItem();
109  switch (ParentItem.getKind()) {
111  const auto *DS = cast<DeclStmt>(ParentItem.getStmt());
112  assert(!cast<VarDecl>(DS->getSingleDecl())->getType().getCanonicalType()
113  ->getAsCXXRecordDecl()->hasTrivialDestructor());
114  return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE);
115  }
117  llvm_unreachable("This context does not accept a bound temporary!");
118  }
120  assert(ParentLayer->isLast());
121  const auto *RS = cast<ReturnStmt>(ParentItem.getStmt());
122  assert(!RS->getRetValue()->getType().getCanonicalType()
123  ->getAsCXXRecordDecl()->hasTrivialDestructor());
124  return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, RS,
125  BTE);
126  }
127 
129  // No assert. We may have an elidable copy on the grandparent layer.
130  const auto *MTE = cast<MaterializeTemporaryExpr>(ParentItem.getStmt());
131  return createMaterializedTemporaryFromLayers(C, MTE, BTE,
132  ParentLayer->getParent());
133  }
135  llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!");
136  }
138  llvm_unreachable("Elided destructor items are not produced by the CFG!");
139  }
141  llvm_unreachable("Materialization is necessary to put temporary into a "
142  "copy or move constructor!");
143  }
145  assert(ParentLayer->isLast());
146  const auto *E = cast<Expr>(ParentItem.getStmt());
147  assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) ||
148  isa<ObjCMessageExpr>(E));
149  return create<ArgumentConstructionContext>(C, E, ParentItem.getIndex(),
150  BTE);
151  }
153  assert(ParentLayer->isLast());
154  const auto *I = ParentItem.getCXXCtorInitializer();
155  assert(!I->getAnyMember()->getType().getCanonicalType()
156  ->getAsCXXRecordDecl()->hasTrivialDestructor());
157  return create<CXX17ElidedCopyConstructorInitializerConstructionContext>(
158  C, I, BTE);
159  }
160  } // switch (ParentItem.getKind())
161 
162  llvm_unreachable("Unexpected construction context with destructor!");
163 }
164 
166  BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
167  // Before this point all we've had was a stockpile of arbitrary layers.
168  // Now validate that it is shaped as one of the finite amount of expected
169  // patterns.
170  const ConstructionContextItem &TopItem = TopLayer->getItem();
171  switch (TopItem.getKind()) {
173  assert(TopLayer->isLast());
174  const auto *DS = cast<DeclStmt>(TopItem.getStmt());
175  return create<SimpleVariableConstructionContext>(C, DS);
176  }
178  assert(TopLayer->isLast());
179  const auto *NE = cast<CXXNewExpr>(TopItem.getStmt());
180  return create<NewAllocatedObjectConstructionContext>(C, NE);
181  }
183  assert(TopLayer->isLast());
184  const auto *RS = cast<ReturnStmt>(TopItem.getStmt());
185  return create<SimpleReturnedValueConstructionContext>(C, RS);
186  }
188  const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt());
189  return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr,
190  TopLayer->getParent());
191  }
193  const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt());
194  assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl()
196  return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent());
197  }
199  llvm_unreachable("Elided destructor items are not produced by the CFG!");
200  }
202  llvm_unreachable("The argument needs to be materialized first!");
203  }
205  assert(TopLayer->isLast());
206  const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
207  return create<SimpleConstructorInitializerConstructionContext>(C, I);
208  }
210  assert(TopLayer->isLast());
211  const auto *E = cast<Expr>(TopItem.getStmt());
212  return create<ArgumentConstructionContext>(C, E, TopItem.getIndex(),
213  /*BTE=*/nullptr);
214  }
215  } // switch (TopItem.getKind())
216  llvm_unreachable("Unexpected construction context!");
217 }
Represents a call to a C++ constructor.
Definition: ExprCXX.h:1262
bool isStrictlyMoreSpecificThan(const ConstructionContextLayer *Other) const
See if Other is a proper initial segment of this construction context in terms of the parent chain - ...
Represents a prvalue temporary that is written into memory so that a reference can bind to it...
Definition: ExprCXX.h:4068
llvm::BumpPtrAllocator & getAllocator()
Definition: BumpVector.h:56
const ConstructionContextLayer * getParent() const
Represents binding an expression to a temporary.
Definition: ExprCXX.h:1217
bool hasTrivialDestructor() const
Determine whether this class has a trivial destructor (C++ [class.dtor]p3)
Definition: DeclCXX.h:1478
NodeId Parent
Definition: ASTDiff.cpp:192
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1605
QualType getType() const
Definition: Expr.h:128
bool hasNonTrivialDestructor() const
Determine whether this class has a non-trivial destructor (C++ [class.dtor]p3)
Definition: DeclCXX.h:1488
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Definition: ExprCXX.h:4112
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 getCanonicalType() const
Definition: Type.h:6097
Construction context can be seen as a linked list of multiple layers.
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...
Dataflow Directional Tag Classes.
Represents a single point (AST node) in the program that requires attention during construction of an...
Represents a C++ base or member initializer.
Definition: DeclCXX.h:2253
const ConstructionContextItem & getItem() const
static const ConstructionContextLayer * create(BumpVectorContext &C, const ConstructionContextItem &Item, const ConstructionContextLayer *Parent=nullptr)
const Stmt * getStmt() const
The construction site - the statement that triggered the construction for one of its parts...
ConstructionContext&#39;s subclasses describe different ways of constructing an object in C++...
Full-expression storage duration (for temporaries).
Definition: Specifiers.h:277