brintos

brintos / llvm-project-archived public Read only

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