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 17 #include "clang/Analysis/ConstructionContext.h" 18 #include "clang/AST/ExprObjC.h" 19 20 using namespace clang; 21 22 const ConstructionContextLayer * 23 ConstructionContextLayer::create(BumpVectorContext &C, 24 const ConstructionContextItem &Item, 25 const ConstructionContextLayer *Parent) { 26 ConstructionContextLayer *CC = 27 C.getAllocator().Allocate<ConstructionContextLayer>(); 28 return new (CC) ConstructionContextLayer(Item, Parent); 29 } 30 31 bool ConstructionContextLayer::isStrictlyMoreSpecificThan( 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( 47 BumpVectorContext &C, const MaterializeTemporaryExpr *MTE, 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() 56 ->hasTrivialDestructor() || 57 MTE->getStorageDuration() != SD_FullExpression)) { 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() == 74 ConstructionContextItem::ElidableConstructorKind); 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( 97 BumpVectorContext &C, const CXXBindTemporaryExpr *BTE, 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()) { 110 case ConstructionContextItem::VariableKind: { 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 } 116 case ConstructionContextItem::NewAllocatorKind: { 117 llvm_unreachable("This context does not accept a bound temporary!"); 118 } 119 case ConstructionContextItem::ReturnKind: { 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 128 case ConstructionContextItem::MaterializationKind: { 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 } 134 case ConstructionContextItem::TemporaryDestructorKind: { 135 llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!"); 136 } 137 case ConstructionContextItem::ElidedDestructorKind: { 138 llvm_unreachable("Elided destructor items are not produced by the CFG!"); 139 } 140 case ConstructionContextItem::ElidableConstructorKind: { 141 llvm_unreachable("Materialization is necessary to put temporary into a " 142 "copy or move constructor!"); 143 } 144 case ConstructionContextItem::ArgumentKind: { 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 } 152 case ConstructionContextItem::InitializerKind: { 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 165 const ConstructionContext *ConstructionContext::createFromLayers( 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()) { 172 case ConstructionContextItem::VariableKind: { 173 assert(TopLayer->isLast()); 174 const auto *DS = cast<DeclStmt>(TopItem.getStmt()); 175 return create<SimpleVariableConstructionContext>(C, DS); 176 } 177 case ConstructionContextItem::NewAllocatorKind: { 178 assert(TopLayer->isLast()); 179 const auto *NE = cast<CXXNewExpr>(TopItem.getStmt()); 180 return create<NewAllocatedObjectConstructionContext>(C, NE); 181 } 182 case ConstructionContextItem::ReturnKind: { 183 assert(TopLayer->isLast()); 184 const auto *RS = cast<ReturnStmt>(TopItem.getStmt()); 185 return create<SimpleReturnedValueConstructionContext>(C, RS); 186 } 187 case ConstructionContextItem::MaterializationKind: { 188 const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt()); 189 return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr, 190 TopLayer->getParent()); 191 } 192 case ConstructionContextItem::TemporaryDestructorKind: { 193 const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt()); 194 assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl() 195 ->hasNonTrivialDestructor()); 196 return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent()); 197 } 198 case ConstructionContextItem::ElidedDestructorKind: { 199 llvm_unreachable("Elided destructor items are not produced by the CFG!"); 200 } 201 case ConstructionContextItem::ElidableConstructorKind: { 202 llvm_unreachable("The argument needs to be materialized first!"); 203 } 204 case ConstructionContextItem::InitializerKind: { 205 assert(TopLayer->isLast()); 206 const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer(); 207 return create<SimpleConstructorInitializerConstructionContext>(C, I); 208 } 209 case ConstructionContextItem::ArgumentKind: { 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 } 218