Home | History | Annotate | Line # | Download | only in Analysis
      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