1 1.1 joerg //===- ConstructionContext.cpp - CFG constructor information --------------===// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // 9 1.1 joerg // This file defines the ConstructionContext class and its sub-classes, 10 1.1 joerg // which represent various different ways of constructing C++ objects 11 1.1 joerg // with the additional information the users may want to know about 12 1.1 joerg // the constructor. 13 1.1 joerg // 14 1.1 joerg //===----------------------------------------------------------------------===// 15 1.1 joerg 16 1.1 joerg #include "clang/Analysis/ConstructionContext.h" 17 1.1 joerg #include "clang/AST/ExprObjC.h" 18 1.1 joerg 19 1.1 joerg using namespace clang; 20 1.1 joerg 21 1.1 joerg const ConstructionContextLayer * 22 1.1 joerg ConstructionContextLayer::create(BumpVectorContext &C, 23 1.1 joerg const ConstructionContextItem &Item, 24 1.1 joerg const ConstructionContextLayer *Parent) { 25 1.1 joerg ConstructionContextLayer *CC = 26 1.1 joerg C.getAllocator().Allocate<ConstructionContextLayer>(); 27 1.1 joerg return new (CC) ConstructionContextLayer(Item, Parent); 28 1.1 joerg } 29 1.1 joerg 30 1.1 joerg bool ConstructionContextLayer::isStrictlyMoreSpecificThan( 31 1.1 joerg const ConstructionContextLayer *Other) const { 32 1.1 joerg const ConstructionContextLayer *Self = this; 33 1.1 joerg while (true) { 34 1.1 joerg if (!Other) 35 1.1 joerg return Self; 36 1.1 joerg if (!Self || !(Self->Item == Other->Item)) 37 1.1 joerg return false; 38 1.1 joerg Self = Self->getParent(); 39 1.1 joerg Other = Other->getParent(); 40 1.1 joerg } 41 1.1 joerg llvm_unreachable("The above loop can only be terminated via return!"); 42 1.1 joerg } 43 1.1 joerg 44 1.1 joerg const ConstructionContext * 45 1.1 joerg ConstructionContext::createMaterializedTemporaryFromLayers( 46 1.1 joerg BumpVectorContext &C, const MaterializeTemporaryExpr *MTE, 47 1.1 joerg const CXXBindTemporaryExpr *BTE, 48 1.1 joerg const ConstructionContextLayer *ParentLayer) { 49 1.1 joerg assert(MTE); 50 1.1 joerg 51 1.1 joerg // If the object requires destruction and is not lifetime-extended, 52 1.1 joerg // then it must have a BTE within its MTE, otherwise it shouldn't. 53 1.1 joerg // FIXME: This should be an assertion. 54 1.1 joerg if (!BTE && !(MTE->getType().getCanonicalType()->getAsCXXRecordDecl() 55 1.1 joerg ->hasTrivialDestructor() || 56 1.1 joerg MTE->getStorageDuration() != SD_FullExpression)) { 57 1.1 joerg return nullptr; 58 1.1 joerg } 59 1.1 joerg 60 1.1 joerg // If the temporary is lifetime-extended, don't save the BTE, 61 1.1 joerg // because we don't need a temporary destructor, but an automatic 62 1.1 joerg // destructor. 63 1.1 joerg if (MTE->getStorageDuration() != SD_FullExpression) { 64 1.1 joerg BTE = nullptr; 65 1.1 joerg } 66 1.1 joerg 67 1.1 joerg // Handle pre-C++17 copy and move elision. 68 1.1 joerg const CXXConstructExpr *ElidedCE = nullptr; 69 1.1 joerg const ConstructionContext *ElidedCC = nullptr; 70 1.1 joerg if (ParentLayer) { 71 1.1 joerg const ConstructionContextItem &ElidedItem = ParentLayer->getItem(); 72 1.1 joerg assert(ElidedItem.getKind() == 73 1.1 joerg ConstructionContextItem::ElidableConstructorKind); 74 1.1 joerg ElidedCE = cast<CXXConstructExpr>(ElidedItem.getStmt()); 75 1.1 joerg assert(ElidedCE->isElidable()); 76 1.1 joerg // We're creating a construction context that might have already 77 1.1 joerg // been created elsewhere. Maybe we should unique our construction 78 1.1 joerg // contexts. That's what we often do, but in this case it's unlikely 79 1.1 joerg // to bring any benefits. 80 1.1 joerg ElidedCC = createFromLayers(C, ParentLayer->getParent()); 81 1.1 joerg if (!ElidedCC) { 82 1.1 joerg // We may fail to create the elided construction context. 83 1.1 joerg // In this case, skip copy elision entirely. 84 1.1 joerg return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE); 85 1.1 joerg } 86 1.1 joerg return create<ElidedTemporaryObjectConstructionContext>( 87 1.1 joerg C, BTE, MTE, ElidedCE, ElidedCC); 88 1.1 joerg } 89 1.1 joerg 90 1.1 joerg // This is a normal temporary. 91 1.1 joerg assert(!ParentLayer); 92 1.1 joerg return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE); 93 1.1 joerg } 94 1.1 joerg 95 1.1 joerg const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers( 96 1.1 joerg BumpVectorContext &C, const CXXBindTemporaryExpr *BTE, 97 1.1 joerg const ConstructionContextLayer *ParentLayer) { 98 1.1 joerg if (!ParentLayer) { 99 1.1 joerg // A temporary object that doesn't require materialization. 100 1.1 joerg // In particular, it shouldn't require copy elision, because 101 1.1 joerg // copy/move constructors take a reference, which requires 102 1.1 joerg // materialization to obtain the glvalue. 103 1.1 joerg return create<SimpleTemporaryObjectConstructionContext>(C, BTE, 104 1.1 joerg /*MTE=*/nullptr); 105 1.1 joerg } 106 1.1 joerg 107 1.1 joerg const ConstructionContextItem &ParentItem = ParentLayer->getItem(); 108 1.1 joerg switch (ParentItem.getKind()) { 109 1.1 joerg case ConstructionContextItem::VariableKind: { 110 1.1 joerg const auto *DS = cast<DeclStmt>(ParentItem.getStmt()); 111 1.1 joerg assert(!cast<VarDecl>(DS->getSingleDecl())->getType().getCanonicalType() 112 1.1 joerg ->getAsCXXRecordDecl()->hasTrivialDestructor()); 113 1.1 joerg return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE); 114 1.1 joerg } 115 1.1 joerg case ConstructionContextItem::NewAllocatorKind: { 116 1.1 joerg llvm_unreachable("This context does not accept a bound temporary!"); 117 1.1 joerg } 118 1.1 joerg case ConstructionContextItem::ReturnKind: { 119 1.1 joerg assert(ParentLayer->isLast()); 120 1.1 joerg const auto *RS = cast<ReturnStmt>(ParentItem.getStmt()); 121 1.1 joerg assert(!RS->getRetValue()->getType().getCanonicalType() 122 1.1 joerg ->getAsCXXRecordDecl()->hasTrivialDestructor()); 123 1.1 joerg return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, RS, 124 1.1 joerg BTE); 125 1.1 joerg } 126 1.1 joerg 127 1.1 joerg case ConstructionContextItem::MaterializationKind: { 128 1.1 joerg // No assert. We may have an elidable copy on the grandparent layer. 129 1.1 joerg const auto *MTE = cast<MaterializeTemporaryExpr>(ParentItem.getStmt()); 130 1.1 joerg return createMaterializedTemporaryFromLayers(C, MTE, BTE, 131 1.1 joerg ParentLayer->getParent()); 132 1.1 joerg } 133 1.1 joerg case ConstructionContextItem::TemporaryDestructorKind: { 134 1.1 joerg llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!"); 135 1.1 joerg } 136 1.1 joerg case ConstructionContextItem::ElidedDestructorKind: { 137 1.1 joerg llvm_unreachable("Elided destructor items are not produced by the CFG!"); 138 1.1 joerg } 139 1.1 joerg case ConstructionContextItem::ElidableConstructorKind: { 140 1.1 joerg llvm_unreachable("Materialization is necessary to put temporary into a " 141 1.1 joerg "copy or move constructor!"); 142 1.1 joerg } 143 1.1 joerg case ConstructionContextItem::ArgumentKind: { 144 1.1 joerg assert(ParentLayer->isLast()); 145 1.1 joerg const auto *E = cast<Expr>(ParentItem.getStmt()); 146 1.1 joerg assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) || 147 1.1 joerg isa<ObjCMessageExpr>(E)); 148 1.1 joerg return create<ArgumentConstructionContext>(C, E, ParentItem.getIndex(), 149 1.1 joerg BTE); 150 1.1 joerg } 151 1.1 joerg case ConstructionContextItem::InitializerKind: { 152 1.1 joerg assert(ParentLayer->isLast()); 153 1.1 joerg const auto *I = ParentItem.getCXXCtorInitializer(); 154 1.1 joerg assert(!I->getAnyMember()->getType().getCanonicalType() 155 1.1 joerg ->getAsCXXRecordDecl()->hasTrivialDestructor()); 156 1.1 joerg return create<CXX17ElidedCopyConstructorInitializerConstructionContext>( 157 1.1 joerg C, I, BTE); 158 1.1 joerg } 159 1.1 joerg } // switch (ParentItem.getKind()) 160 1.1 joerg 161 1.1 joerg llvm_unreachable("Unexpected construction context with destructor!"); 162 1.1 joerg } 163 1.1 joerg 164 1.1 joerg const ConstructionContext *ConstructionContext::createFromLayers( 165 1.1 joerg BumpVectorContext &C, const ConstructionContextLayer *TopLayer) { 166 1.1 joerg // Before this point all we've had was a stockpile of arbitrary layers. 167 1.1 joerg // Now validate that it is shaped as one of the finite amount of expected 168 1.1 joerg // patterns. 169 1.1 joerg const ConstructionContextItem &TopItem = TopLayer->getItem(); 170 1.1 joerg switch (TopItem.getKind()) { 171 1.1 joerg case ConstructionContextItem::VariableKind: { 172 1.1 joerg assert(TopLayer->isLast()); 173 1.1 joerg const auto *DS = cast<DeclStmt>(TopItem.getStmt()); 174 1.1 joerg return create<SimpleVariableConstructionContext>(C, DS); 175 1.1 joerg } 176 1.1 joerg case ConstructionContextItem::NewAllocatorKind: { 177 1.1 joerg assert(TopLayer->isLast()); 178 1.1 joerg const auto *NE = cast<CXXNewExpr>(TopItem.getStmt()); 179 1.1 joerg return create<NewAllocatedObjectConstructionContext>(C, NE); 180 1.1 joerg } 181 1.1 joerg case ConstructionContextItem::ReturnKind: { 182 1.1 joerg assert(TopLayer->isLast()); 183 1.1 joerg const auto *RS = cast<ReturnStmt>(TopItem.getStmt()); 184 1.1 joerg return create<SimpleReturnedValueConstructionContext>(C, RS); 185 1.1 joerg } 186 1.1 joerg case ConstructionContextItem::MaterializationKind: { 187 1.1 joerg const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt()); 188 1.1 joerg return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr, 189 1.1 joerg TopLayer->getParent()); 190 1.1 joerg } 191 1.1 joerg case ConstructionContextItem::TemporaryDestructorKind: { 192 1.1 joerg const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt()); 193 1.1 joerg assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl() 194 1.1 joerg ->hasNonTrivialDestructor()); 195 1.1 joerg return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent()); 196 1.1 joerg } 197 1.1 joerg case ConstructionContextItem::ElidedDestructorKind: { 198 1.1 joerg llvm_unreachable("Elided destructor items are not produced by the CFG!"); 199 1.1 joerg } 200 1.1 joerg case ConstructionContextItem::ElidableConstructorKind: { 201 1.1 joerg llvm_unreachable("The argument needs to be materialized first!"); 202 1.1 joerg } 203 1.1 joerg case ConstructionContextItem::InitializerKind: { 204 1.1 joerg assert(TopLayer->isLast()); 205 1.1 joerg const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer(); 206 1.1 joerg return create<SimpleConstructorInitializerConstructionContext>(C, I); 207 1.1 joerg } 208 1.1 joerg case ConstructionContextItem::ArgumentKind: { 209 1.1 joerg assert(TopLayer->isLast()); 210 1.1 joerg const auto *E = cast<Expr>(TopItem.getStmt()); 211 1.1 joerg return create<ArgumentConstructionContext>(C, E, TopItem.getIndex(), 212 1.1 joerg /*BTE=*/nullptr); 213 1.1 joerg } 214 1.1 joerg } // switch (TopItem.getKind()) 215 1.1 joerg llvm_unreachable("Unexpected construction context!"); 216 1.1 joerg } 217