xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/ConstructionContext.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
10b57cec5SDimitry Andric //===- ConstructionContext.cpp - CFG constructor information --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the ConstructionContext class and its sub-classes,
100b57cec5SDimitry Andric // which represent various different ways of constructing C++ objects
110b57cec5SDimitry Andric // with the additional information the users may want to know about
120b57cec5SDimitry Andric // the constructor.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "clang/Analysis/ConstructionContext.h"
170b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace clang;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric const ConstructionContextLayer *
create(BumpVectorContext & C,const ConstructionContextItem & Item,const ConstructionContextLayer * Parent)220b57cec5SDimitry Andric ConstructionContextLayer::create(BumpVectorContext &C,
230b57cec5SDimitry Andric                                  const ConstructionContextItem &Item,
240b57cec5SDimitry Andric                                  const ConstructionContextLayer *Parent) {
250b57cec5SDimitry Andric   ConstructionContextLayer *CC =
260b57cec5SDimitry Andric       C.getAllocator().Allocate<ConstructionContextLayer>();
270b57cec5SDimitry Andric   return new (CC) ConstructionContextLayer(Item, Parent);
280b57cec5SDimitry Andric }
290b57cec5SDimitry Andric 
isStrictlyMoreSpecificThan(const ConstructionContextLayer * Other) const300b57cec5SDimitry Andric bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
310b57cec5SDimitry Andric     const ConstructionContextLayer *Other) const {
320b57cec5SDimitry Andric   const ConstructionContextLayer *Self = this;
330b57cec5SDimitry Andric   while (true) {
340b57cec5SDimitry Andric     if (!Other)
350b57cec5SDimitry Andric       return Self;
360b57cec5SDimitry Andric     if (!Self || !(Self->Item == Other->Item))
370b57cec5SDimitry Andric       return false;
380b57cec5SDimitry Andric     Self = Self->getParent();
390b57cec5SDimitry Andric     Other = Other->getParent();
400b57cec5SDimitry Andric   }
410b57cec5SDimitry Andric   llvm_unreachable("The above loop can only be terminated via return!");
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric const ConstructionContext *
createMaterializedTemporaryFromLayers(BumpVectorContext & C,const MaterializeTemporaryExpr * MTE,const CXXBindTemporaryExpr * BTE,const ConstructionContextLayer * ParentLayer)450b57cec5SDimitry Andric ConstructionContext::createMaterializedTemporaryFromLayers(
460b57cec5SDimitry Andric     BumpVectorContext &C, const MaterializeTemporaryExpr *MTE,
470b57cec5SDimitry Andric     const CXXBindTemporaryExpr *BTE,
480b57cec5SDimitry Andric     const ConstructionContextLayer *ParentLayer) {
490b57cec5SDimitry Andric   assert(MTE);
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   // If the object requires destruction and is not lifetime-extended,
520b57cec5SDimitry Andric   // then it must have a BTE within its MTE, otherwise it shouldn't.
530b57cec5SDimitry Andric   // FIXME: This should be an assertion.
540b57cec5SDimitry Andric   if (!BTE && !(MTE->getType().getCanonicalType()->getAsCXXRecordDecl()
550b57cec5SDimitry Andric                     ->hasTrivialDestructor() ||
560b57cec5SDimitry Andric                 MTE->getStorageDuration() != SD_FullExpression)) {
570b57cec5SDimitry Andric     return nullptr;
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   // If the temporary is lifetime-extended, don't save the BTE,
610b57cec5SDimitry Andric   // because we don't need a temporary destructor, but an automatic
620b57cec5SDimitry Andric   // destructor.
630b57cec5SDimitry Andric   if (MTE->getStorageDuration() != SD_FullExpression) {
640b57cec5SDimitry Andric     BTE = nullptr;
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   // Handle pre-C++17 copy and move elision.
680b57cec5SDimitry Andric   const CXXConstructExpr *ElidedCE = nullptr;
690b57cec5SDimitry Andric   const ConstructionContext *ElidedCC = nullptr;
700b57cec5SDimitry Andric   if (ParentLayer) {
710b57cec5SDimitry Andric     const ConstructionContextItem &ElidedItem = ParentLayer->getItem();
720b57cec5SDimitry Andric     assert(ElidedItem.getKind() ==
730b57cec5SDimitry Andric            ConstructionContextItem::ElidableConstructorKind);
740b57cec5SDimitry Andric     ElidedCE = cast<CXXConstructExpr>(ElidedItem.getStmt());
750b57cec5SDimitry Andric     assert(ElidedCE->isElidable());
760b57cec5SDimitry Andric     // We're creating a construction context that might have already
770b57cec5SDimitry Andric     // been created elsewhere. Maybe we should unique our construction
780b57cec5SDimitry Andric     // contexts. That's what we often do, but in this case it's unlikely
790b57cec5SDimitry Andric     // to bring any benefits.
800b57cec5SDimitry Andric     ElidedCC = createFromLayers(C, ParentLayer->getParent());
810b57cec5SDimitry Andric     if (!ElidedCC) {
820b57cec5SDimitry Andric       // We may fail to create the elided construction context.
830b57cec5SDimitry Andric       // In this case, skip copy elision entirely.
840b57cec5SDimitry Andric       return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
850b57cec5SDimitry Andric     }
860b57cec5SDimitry Andric     return create<ElidedTemporaryObjectConstructionContext>(
870b57cec5SDimitry Andric         C, BTE, MTE, ElidedCE, ElidedCC);
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   // This is a normal temporary.
910b57cec5SDimitry Andric   assert(!ParentLayer);
920b57cec5SDimitry Andric   return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
createBoundTemporaryFromLayers(BumpVectorContext & C,const CXXBindTemporaryExpr * BTE,const ConstructionContextLayer * ParentLayer)950b57cec5SDimitry Andric const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers(
960b57cec5SDimitry Andric     BumpVectorContext &C, const CXXBindTemporaryExpr *BTE,
970b57cec5SDimitry Andric     const ConstructionContextLayer *ParentLayer) {
980b57cec5SDimitry Andric   if (!ParentLayer) {
990b57cec5SDimitry Andric     // A temporary object that doesn't require materialization.
1000b57cec5SDimitry Andric     // In particular, it shouldn't require copy elision, because
1010b57cec5SDimitry Andric     // copy/move constructors take a reference, which requires
1020b57cec5SDimitry Andric     // materialization to obtain the glvalue.
1030b57cec5SDimitry Andric     return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
1040b57cec5SDimitry Andric                                                             /*MTE=*/nullptr);
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   const ConstructionContextItem &ParentItem = ParentLayer->getItem();
1080b57cec5SDimitry Andric   switch (ParentItem.getKind()) {
1090b57cec5SDimitry Andric   case ConstructionContextItem::VariableKind: {
1100b57cec5SDimitry Andric     const auto *DS = cast<DeclStmt>(ParentItem.getStmt());
1110b57cec5SDimitry Andric     assert(!cast<VarDecl>(DS->getSingleDecl())->getType().getCanonicalType()
1120b57cec5SDimitry Andric                             ->getAsCXXRecordDecl()->hasTrivialDestructor());
1130b57cec5SDimitry Andric     return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE);
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric   case ConstructionContextItem::NewAllocatorKind: {
1160b57cec5SDimitry Andric     llvm_unreachable("This context does not accept a bound temporary!");
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric   case ConstructionContextItem::ReturnKind: {
1190b57cec5SDimitry Andric     assert(ParentLayer->isLast());
1200b57cec5SDimitry Andric     const auto *RS = cast<ReturnStmt>(ParentItem.getStmt());
1210b57cec5SDimitry Andric     assert(!RS->getRetValue()->getType().getCanonicalType()
1220b57cec5SDimitry Andric               ->getAsCXXRecordDecl()->hasTrivialDestructor());
1230b57cec5SDimitry Andric     return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, RS,
1240b57cec5SDimitry Andric                                                                    BTE);
1250b57cec5SDimitry Andric   }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   case ConstructionContextItem::MaterializationKind: {
1280b57cec5SDimitry Andric     // No assert. We may have an elidable copy on the grandparent layer.
1290b57cec5SDimitry Andric     const auto *MTE = cast<MaterializeTemporaryExpr>(ParentItem.getStmt());
1300b57cec5SDimitry Andric     return createMaterializedTemporaryFromLayers(C, MTE, BTE,
1310b57cec5SDimitry Andric                                                  ParentLayer->getParent());
1320b57cec5SDimitry Andric   }
1330b57cec5SDimitry Andric   case ConstructionContextItem::TemporaryDestructorKind: {
1340b57cec5SDimitry Andric     llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!");
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric   case ConstructionContextItem::ElidedDestructorKind: {
1370b57cec5SDimitry Andric     llvm_unreachable("Elided destructor items are not produced by the CFG!");
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric   case ConstructionContextItem::ElidableConstructorKind: {
1400b57cec5SDimitry Andric     llvm_unreachable("Materialization is necessary to put temporary into a "
1410b57cec5SDimitry Andric                      "copy or move constructor!");
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric   case ConstructionContextItem::ArgumentKind: {
1440b57cec5SDimitry Andric     assert(ParentLayer->isLast());
1450b57cec5SDimitry Andric     const auto *E = cast<Expr>(ParentItem.getStmt());
1460b57cec5SDimitry Andric     assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) ||
1470b57cec5SDimitry Andric            isa<ObjCMessageExpr>(E));
1480b57cec5SDimitry Andric     return create<ArgumentConstructionContext>(C, E, ParentItem.getIndex(),
1490b57cec5SDimitry Andric                                                BTE);
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric   case ConstructionContextItem::InitializerKind: {
1520b57cec5SDimitry Andric     assert(ParentLayer->isLast());
1530b57cec5SDimitry Andric     const auto *I = ParentItem.getCXXCtorInitializer();
1540b57cec5SDimitry Andric     assert(!I->getAnyMember()->getType().getCanonicalType()
1550b57cec5SDimitry Andric              ->getAsCXXRecordDecl()->hasTrivialDestructor());
1560b57cec5SDimitry Andric     return create<CXX17ElidedCopyConstructorInitializerConstructionContext>(
1570b57cec5SDimitry Andric         C, I, BTE);
1580b57cec5SDimitry Andric   }
159*972a253aSDimitry Andric   case ConstructionContextItem::LambdaCaptureKind: {
160*972a253aSDimitry Andric     assert(ParentLayer->isLast());
161*972a253aSDimitry Andric     const auto *E = cast<LambdaExpr>(ParentItem.getStmt());
162*972a253aSDimitry Andric     return create<LambdaCaptureConstructionContext>(C, E,
163*972a253aSDimitry Andric                                                     ParentItem.getIndex());
164*972a253aSDimitry Andric   }
1650b57cec5SDimitry Andric   } // switch (ParentItem.getKind())
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   llvm_unreachable("Unexpected construction context with destructor!");
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
createFromLayers(BumpVectorContext & C,const ConstructionContextLayer * TopLayer)1700b57cec5SDimitry Andric const ConstructionContext *ConstructionContext::createFromLayers(
1710b57cec5SDimitry Andric     BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
1720b57cec5SDimitry Andric   // Before this point all we've had was a stockpile of arbitrary layers.
1730b57cec5SDimitry Andric   // Now validate that it is shaped as one of the finite amount of expected
1740b57cec5SDimitry Andric   // patterns.
1750b57cec5SDimitry Andric   const ConstructionContextItem &TopItem = TopLayer->getItem();
1760b57cec5SDimitry Andric   switch (TopItem.getKind()) {
1770b57cec5SDimitry Andric   case ConstructionContextItem::VariableKind: {
1780b57cec5SDimitry Andric     assert(TopLayer->isLast());
1790b57cec5SDimitry Andric     const auto *DS = cast<DeclStmt>(TopItem.getStmt());
1800b57cec5SDimitry Andric     return create<SimpleVariableConstructionContext>(C, DS);
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric   case ConstructionContextItem::NewAllocatorKind: {
1830b57cec5SDimitry Andric     assert(TopLayer->isLast());
1840b57cec5SDimitry Andric     const auto *NE = cast<CXXNewExpr>(TopItem.getStmt());
1850b57cec5SDimitry Andric     return create<NewAllocatedObjectConstructionContext>(C, NE);
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric   case ConstructionContextItem::ReturnKind: {
1880b57cec5SDimitry Andric     assert(TopLayer->isLast());
1890b57cec5SDimitry Andric     const auto *RS = cast<ReturnStmt>(TopItem.getStmt());
1900b57cec5SDimitry Andric     return create<SimpleReturnedValueConstructionContext>(C, RS);
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric   case ConstructionContextItem::MaterializationKind: {
1930b57cec5SDimitry Andric     const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt());
1940b57cec5SDimitry Andric     return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr,
1950b57cec5SDimitry Andric                                                  TopLayer->getParent());
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric   case ConstructionContextItem::TemporaryDestructorKind: {
1980b57cec5SDimitry Andric     const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt());
1990b57cec5SDimitry Andric     assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl()
2000b57cec5SDimitry Andric               ->hasNonTrivialDestructor());
2010b57cec5SDimitry Andric     return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent());
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric   case ConstructionContextItem::ElidedDestructorKind: {
2040b57cec5SDimitry Andric     llvm_unreachable("Elided destructor items are not produced by the CFG!");
2050b57cec5SDimitry Andric   }
2060b57cec5SDimitry Andric   case ConstructionContextItem::ElidableConstructorKind: {
2070b57cec5SDimitry Andric     llvm_unreachable("The argument needs to be materialized first!");
2080b57cec5SDimitry Andric   }
209*972a253aSDimitry Andric   case ConstructionContextItem::LambdaCaptureKind: {
210*972a253aSDimitry Andric     assert(TopLayer->isLast());
211*972a253aSDimitry Andric     const auto *E = cast<LambdaExpr>(TopItem.getStmt());
212*972a253aSDimitry Andric     return create<LambdaCaptureConstructionContext>(C, E, TopItem.getIndex());
213*972a253aSDimitry Andric   }
2140b57cec5SDimitry Andric   case ConstructionContextItem::InitializerKind: {
2150b57cec5SDimitry Andric     assert(TopLayer->isLast());
2160b57cec5SDimitry Andric     const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
2170b57cec5SDimitry Andric     return create<SimpleConstructorInitializerConstructionContext>(C, I);
2180b57cec5SDimitry Andric   }
2190b57cec5SDimitry Andric   case ConstructionContextItem::ArgumentKind: {
2200b57cec5SDimitry Andric     assert(TopLayer->isLast());
2210b57cec5SDimitry Andric     const auto *E = cast<Expr>(TopItem.getStmt());
2220b57cec5SDimitry Andric     return create<ArgumentConstructionContext>(C, E, TopItem.getIndex(),
2230b57cec5SDimitry Andric                                                /*BTE=*/nullptr);
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric   } // switch (TopItem.getKind())
2260b57cec5SDimitry Andric   llvm_unreachable("Unexpected construction context!");
2270b57cec5SDimitry Andric }
228