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