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