Mercurial > hg > CbC > CbC_llvm
view clang/lib/Analysis/ConstructionContext.cpp @ 222:81f6424ef0e3 llvm-original
LLVM original branch
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 18 Jul 2021 22:10:01 +0900 |
parents | 1d019706d866 |
children | c4bab56944e8 |
line wrap: on
line source
//===- ConstructionContext.cpp - CFG constructor information --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the ConstructionContext class and its sub-classes, // which represent various different ways of constructing C++ objects // with the additional information the users may want to know about // the constructor. // //===----------------------------------------------------------------------===// #include "clang/Analysis/ConstructionContext.h" #include "clang/AST/ExprObjC.h" using namespace clang; const ConstructionContextLayer * ConstructionContextLayer::create(BumpVectorContext &C, const ConstructionContextItem &Item, const ConstructionContextLayer *Parent) { ConstructionContextLayer *CC = C.getAllocator().Allocate<ConstructionContextLayer>(); return new (CC) ConstructionContextLayer(Item, Parent); } bool ConstructionContextLayer::isStrictlyMoreSpecificThan( const ConstructionContextLayer *Other) const { const ConstructionContextLayer *Self = this; while (true) { if (!Other) return Self; if (!Self || !(Self->Item == Other->Item)) return false; Self = Self->getParent(); Other = Other->getParent(); } llvm_unreachable("The above loop can only be terminated via return!"); } const ConstructionContext * ConstructionContext::createMaterializedTemporaryFromLayers( BumpVectorContext &C, const MaterializeTemporaryExpr *MTE, const CXXBindTemporaryExpr *BTE, const ConstructionContextLayer *ParentLayer) { assert(MTE); // If the object requires destruction and is not lifetime-extended, // then it must have a BTE within its MTE, otherwise it shouldn't. // FIXME: This should be an assertion. if (!BTE && !(MTE->getType().getCanonicalType()->getAsCXXRecordDecl() ->hasTrivialDestructor() || MTE->getStorageDuration() != SD_FullExpression)) { return nullptr; } // If the temporary is lifetime-extended, don't save the BTE, // because we don't need a temporary destructor, but an automatic // destructor. if (MTE->getStorageDuration() != SD_FullExpression) { BTE = nullptr; } // Handle pre-C++17 copy and move elision. const CXXConstructExpr *ElidedCE = nullptr; const ConstructionContext *ElidedCC = nullptr; if (ParentLayer) { const ConstructionContextItem &ElidedItem = ParentLayer->getItem(); assert(ElidedItem.getKind() == ConstructionContextItem::ElidableConstructorKind); ElidedCE = cast<CXXConstructExpr>(ElidedItem.getStmt()); assert(ElidedCE->isElidable()); // We're creating a construction context that might have already // been created elsewhere. Maybe we should unique our construction // contexts. That's what we often do, but in this case it's unlikely // to bring any benefits. ElidedCC = createFromLayers(C, ParentLayer->getParent()); if (!ElidedCC) { // We may fail to create the elided construction context. // In this case, skip copy elision entirely. return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE); } return create<ElidedTemporaryObjectConstructionContext>( C, BTE, MTE, ElidedCE, ElidedCC); } // This is a normal temporary. assert(!ParentLayer); return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE); } const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers( BumpVectorContext &C, const CXXBindTemporaryExpr *BTE, const ConstructionContextLayer *ParentLayer) { if (!ParentLayer) { // A temporary object that doesn't require materialization. // In particular, it shouldn't require copy elision, because // copy/move constructors take a reference, which requires // materialization to obtain the glvalue. return create<SimpleTemporaryObjectConstructionContext>(C, BTE, /*MTE=*/nullptr); } const ConstructionContextItem &ParentItem = ParentLayer->getItem(); switch (ParentItem.getKind()) { case ConstructionContextItem::VariableKind: { const auto *DS = cast<DeclStmt>(ParentItem.getStmt()); assert(!cast<VarDecl>(DS->getSingleDecl())->getType().getCanonicalType() ->getAsCXXRecordDecl()->hasTrivialDestructor()); return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE); } case ConstructionContextItem::NewAllocatorKind: { llvm_unreachable("This context does not accept a bound temporary!"); } case ConstructionContextItem::ReturnKind: { assert(ParentLayer->isLast()); const auto *RS = cast<ReturnStmt>(ParentItem.getStmt()); assert(!RS->getRetValue()->getType().getCanonicalType() ->getAsCXXRecordDecl()->hasTrivialDestructor()); return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, RS, BTE); } case ConstructionContextItem::MaterializationKind: { // No assert. We may have an elidable copy on the grandparent layer. const auto *MTE = cast<MaterializeTemporaryExpr>(ParentItem.getStmt()); return createMaterializedTemporaryFromLayers(C, MTE, BTE, ParentLayer->getParent()); } case ConstructionContextItem::TemporaryDestructorKind: { llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!"); } case ConstructionContextItem::ElidedDestructorKind: { llvm_unreachable("Elided destructor items are not produced by the CFG!"); } case ConstructionContextItem::ElidableConstructorKind: { llvm_unreachable("Materialization is necessary to put temporary into a " "copy or move constructor!"); } case ConstructionContextItem::ArgumentKind: { assert(ParentLayer->isLast()); const auto *E = cast<Expr>(ParentItem.getStmt()); assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) || isa<ObjCMessageExpr>(E)); return create<ArgumentConstructionContext>(C, E, ParentItem.getIndex(), BTE); } case ConstructionContextItem::InitializerKind: { assert(ParentLayer->isLast()); const auto *I = ParentItem.getCXXCtorInitializer(); assert(!I->getAnyMember()->getType().getCanonicalType() ->getAsCXXRecordDecl()->hasTrivialDestructor()); return create<CXX17ElidedCopyConstructorInitializerConstructionContext>( C, I, BTE); } } // switch (ParentItem.getKind()) llvm_unreachable("Unexpected construction context with destructor!"); } const ConstructionContext *ConstructionContext::createFromLayers( BumpVectorContext &C, const ConstructionContextLayer *TopLayer) { // Before this point all we've had was a stockpile of arbitrary layers. // Now validate that it is shaped as one of the finite amount of expected // patterns. const ConstructionContextItem &TopItem = TopLayer->getItem(); switch (TopItem.getKind()) { case ConstructionContextItem::VariableKind: { assert(TopLayer->isLast()); const auto *DS = cast<DeclStmt>(TopItem.getStmt()); return create<SimpleVariableConstructionContext>(C, DS); } case ConstructionContextItem::NewAllocatorKind: { assert(TopLayer->isLast()); const auto *NE = cast<CXXNewExpr>(TopItem.getStmt()); return create<NewAllocatedObjectConstructionContext>(C, NE); } case ConstructionContextItem::ReturnKind: { assert(TopLayer->isLast()); const auto *RS = cast<ReturnStmt>(TopItem.getStmt()); return create<SimpleReturnedValueConstructionContext>(C, RS); } case ConstructionContextItem::MaterializationKind: { const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt()); return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr, TopLayer->getParent()); } case ConstructionContextItem::TemporaryDestructorKind: { const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt()); assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl() ->hasNonTrivialDestructor()); return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent()); } case ConstructionContextItem::ElidedDestructorKind: { llvm_unreachable("Elided destructor items are not produced by the CFG!"); } case ConstructionContextItem::ElidableConstructorKind: { llvm_unreachable("The argument needs to be materialized first!"); } case ConstructionContextItem::InitializerKind: { assert(TopLayer->isLast()); const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer(); return create<SimpleConstructorInitializerConstructionContext>(C, I); } case ConstructionContextItem::ArgumentKind: { assert(TopLayer->isLast()); const auto *E = cast<Expr>(TopItem.getStmt()); return create<ArgumentConstructionContext>(C, E, TopItem.getIndex(), /*BTE=*/nullptr); } } // switch (TopItem.getKind()) llvm_unreachable("Unexpected construction context!"); }