ConstructionContext.cpp 9.7 KB

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