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 19 using namespace clang; 20 21 const ConstructionContextLayer * 22 ConstructionContextLayer::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 29 bool 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 43 const 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 assert(ParentLayer->isLast()); 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 return create<TemporaryObjectConstructionContext>(C, BTE, MTE); 81 } 82 // This is a constructor into a function argument. Not implemented yet. 83 if (isa<CallExpr>(ParentLayer->getTriggerStmt())) 84 return nullptr; 85 // This is C++17 copy-elided construction into return statement. 86 if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) { 87 assert(!RS->getRetValue()->getType().getCanonicalType() 88 ->getAsCXXRecordDecl()->hasTrivialDestructor()); 89 return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, 90 RS, BTE); 91 } 92 // This is C++17 copy-elided construction into a simple variable. 93 if (auto *DS = dyn_cast<DeclStmt>(ParentLayer->getTriggerStmt())) { 94 assert(!cast<VarDecl>(DS->getSingleDecl())->getType() 95 .getCanonicalType()->getAsCXXRecordDecl() 96 ->hasTrivialDestructor()); 97 return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE); 98 } 99 llvm_unreachable("Unexpected construction context with destructor!"); 100 } 101 // A temporary object that doesn't require materialization. 102 return create<TemporaryObjectConstructionContext>(C, BTE, /*MTE=*/nullptr); 103 } 104 if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) { 105 // If the object requires destruction and is not lifetime-extended, 106 // then it must have a BTE within its MTE. 107 // FIXME: This should be an assertion. 108 if (!(MTE->getType().getCanonicalType() 109 ->getAsCXXRecordDecl()->hasTrivialDestructor() || 110 MTE->getStorageDuration() != SD_FullExpression)) 111 return nullptr; 112 113 assert(TopLayer->isLast()); 114 return create<TemporaryObjectConstructionContext>(C, nullptr, MTE); 115 } 116 if (const auto *RS = dyn_cast<ReturnStmt>(S)) { 117 assert(TopLayer->isLast()); 118 return create<SimpleReturnedValueConstructionContext>(C, RS); 119 } 120 // This is a constructor into a function argument. Not implemented yet. 121 if (isa<CallExpr>(TopLayer->getTriggerStmt())) 122 return nullptr; 123 llvm_unreachable("Unexpected construction context with statement!"); 124 } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) { 125 assert(TopLayer->isLast()); 126 return create<SimpleConstructorInitializerConstructionContext>(C, I); 127 } 128 llvm_unreachable("Unexpected construction context!"); 129 } 130