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