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, TriggerTy Trigger, 24 unsigned Index, 25 const ConstructionContextLayer *Parent) { 26 ConstructionContextLayer *CC = 27 C.getAllocator().Allocate<ConstructionContextLayer>(); 28 return new (CC) ConstructionContextLayer(Trigger, Index, 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->isSameLayer(Other)) 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 *ConstructionContext::createFromLayers( 46 BumpVectorContext &C, const ConstructionContextLayer *TopLayer) { 47 // Before this point all we've had was a stockpile of arbitrary layers. 48 // Now validate that it is shaped as one of the finite amount of expected 49 // patterns. 50 if (const Stmt *S = TopLayer->getTriggerStmt()) { 51 if (const auto *DS = dyn_cast<DeclStmt>(S)) { 52 assert(TopLayer->isLast()); 53 return create<SimpleVariableConstructionContext>(C, DS); 54 } 55 if (const auto *NE = dyn_cast<CXXNewExpr>(S)) { 56 assert(TopLayer->isLast()); 57 return create<NewAllocatedObjectConstructionContext>(C, NE); 58 } 59 if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(S)) { 60 const MaterializeTemporaryExpr *MTE = nullptr; 61 assert(BTE->getType().getCanonicalType() 62 ->getAsCXXRecordDecl()->hasNonTrivialDestructor()); 63 // For temporaries with destructors, there may or may not be 64 // lifetime extension on the parent layer. 65 if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) { 66 // C++17 *requires* elision of the constructor at the return site 67 // and at variable/member initialization site, while previous standards 68 // were allowing an optional elidable constructor. 69 // This is the C++17 copy-elided construction into a ctor initializer. 70 if (const CXXCtorInitializer *I = ParentLayer->getTriggerInit()) { 71 return create< 72 CXX17ElidedCopyConstructorInitializerConstructionContext>(C, 73 I, BTE); 74 } 75 assert(ParentLayer->getTriggerStmt() && 76 "Non-statement-based layers have been handled above!"); 77 // This is the normal, non-C++17 case: a temporary object which has 78 // both destruction and materialization info attached to it in the AST. 79 if ((MTE = dyn_cast<MaterializeTemporaryExpr>( 80 ParentLayer->getTriggerStmt()))) { 81 if (MTE->getStorageDuration() != SD_FullExpression) { 82 // If the temporary is lifetime-extended, don't save the BTE, 83 // because we don't need a temporary destructor, but an automatic 84 // destructor. 85 BTE = nullptr; 86 } 87 88 // Handle pre-C++17 copy and move elision. 89 const CXXConstructExpr *ElidedCE = nullptr; 90 const ConstructionContext *ElidedCC = nullptr; 91 if (const ConstructionContextLayer *ElidedLayer = 92 ParentLayer->getParent()) { 93 ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt()); 94 assert(ElidedCE->isElidable()); 95 // We're creating a construction context that might have already 96 // been created elsewhere. Maybe we should unique our construction 97 // contexts. That's what we often do, but in this case it's unlikely 98 // to bring any benefits. 99 ElidedCC = createFromLayers(C, ElidedLayer->getParent()); 100 if (!ElidedCC) { 101 // We may fail to create the elided construction context. 102 // In this case, skip copy elision entirely. 103 return create<SimpleTemporaryObjectConstructionContext>(C, BTE, 104 MTE); 105 } else { 106 return create<ElidedTemporaryObjectConstructionContext>( 107 C, BTE, MTE, ElidedCE, ElidedCC); 108 } 109 } 110 assert(ParentLayer->isLast()); 111 return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE); 112 } 113 assert(ParentLayer->isLast()); 114 115 // This is a constructor into a function argument. 116 if (isa<CallExpr>(ParentLayer->getTriggerStmt()) || 117 isa<CXXConstructExpr>(ParentLayer->getTriggerStmt()) || 118 isa<ObjCMessageExpr>(ParentLayer->getTriggerStmt())) { 119 return create<ArgumentConstructionContext>( 120 C, cast<Expr>(ParentLayer->getTriggerStmt()), 121 ParentLayer->getIndex(), BTE); 122 } 123 // This is C++17 copy-elided construction into return statement. 124 if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) { 125 assert(!RS->getRetValue()->getType().getCanonicalType() 126 ->getAsCXXRecordDecl()->hasTrivialDestructor()); 127 return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, 128 RS, BTE); 129 } 130 // This is C++17 copy-elided construction into a simple variable. 131 if (auto *DS = dyn_cast<DeclStmt>(ParentLayer->getTriggerStmt())) { 132 assert(!cast<VarDecl>(DS->getSingleDecl())->getType() 133 .getCanonicalType()->getAsCXXRecordDecl() 134 ->hasTrivialDestructor()); 135 return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE); 136 } 137 llvm_unreachable("Unexpected construction context with destructor!"); 138 } 139 // A temporary object that doesn't require materialization. 140 // In particular, it shouldn't require copy elision, because 141 // copy/move constructors take a reference, which requires 142 // materialization to obtain the glvalue. 143 return create<SimpleTemporaryObjectConstructionContext>(C, BTE, 144 /*MTE=*/nullptr); 145 } 146 if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) { 147 // If the object requires destruction and is not lifetime-extended, 148 // then it must have a BTE within its MTE. 149 // FIXME: This should be an assertion. 150 if (!(MTE->getType().getCanonicalType() 151 ->getAsCXXRecordDecl()->hasTrivialDestructor() || 152 MTE->getStorageDuration() != SD_FullExpression)) 153 return nullptr; 154 155 // Handle pre-C++17 copy and move elision. 156 const CXXConstructExpr *ElidedCE = nullptr; 157 const ConstructionContext *ElidedCC = nullptr; 158 if (const ConstructionContextLayer *ElidedLayer = TopLayer->getParent()) { 159 ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt()); 160 assert(ElidedCE->isElidable()); 161 // We're creating a construction context that might have already 162 // been created elsewhere. Maybe we should unique our construction 163 // contexts. That's what we often do, but in this case it's unlikely 164 // to bring any benefits. 165 ElidedCC = createFromLayers(C, ElidedLayer->getParent()); 166 if (!ElidedCC) { 167 // We may fail to create the elided construction context. 168 // In this case, skip copy elision entirely. 169 return create<SimpleTemporaryObjectConstructionContext>(C, nullptr, 170 MTE); 171 } 172 return create<ElidedTemporaryObjectConstructionContext>( 173 C, nullptr, MTE, ElidedCE, ElidedCC); 174 } 175 assert(TopLayer->isLast()); 176 return create<SimpleTemporaryObjectConstructionContext>(C, nullptr, MTE); 177 } 178 if (const auto *RS = dyn_cast<ReturnStmt>(S)) { 179 assert(TopLayer->isLast()); 180 return create<SimpleReturnedValueConstructionContext>(C, RS); 181 } 182 // This is a constructor into a function argument. 183 if (isa<CallExpr>(TopLayer->getTriggerStmt()) || 184 isa<CXXConstructExpr>(TopLayer->getTriggerStmt()) || 185 isa<ObjCMessageExpr>(TopLayer->getTriggerStmt())) { 186 assert(TopLayer->isLast()); 187 return create<ArgumentConstructionContext>( 188 C, cast<Expr>(TopLayer->getTriggerStmt()), TopLayer->getIndex(), 189 /*BTE=*/nullptr); 190 } 191 llvm_unreachable("Unexpected construction context with statement!"); 192 } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) { 193 assert(TopLayer->isLast()); 194 return create<SimpleConstructorInitializerConstructionContext>(C, I); 195 } 196 llvm_unreachable("Unexpected construction context!"); 197 } 198