| //===- ConstructionContext.h - CFG constructor information ------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // 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. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H |
| #define LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H |
| |
| #include "clang/Analysis/Support/BumpVector.h" |
| #include "clang/AST/ExprCXX.h" |
| |
| namespace clang { |
| |
| /// Represents a single point (AST node) in the program that requires attention |
| /// during construction of an object. ConstructionContext would be represented |
| /// as a list of such items. |
| class ConstructionContextItem { |
| public: |
| enum ItemKind { |
| VariableKind, |
| NewAllocatorKind, |
| ReturnKind, |
| MaterializationKind, |
| TemporaryDestructorKind, |
| ElidedDestructorKind, |
| ElidableConstructorKind, |
| ArgumentKind, |
| STATEMENT_WITH_INDEX_KIND_BEGIN=ArgumentKind, |
| STATEMENT_WITH_INDEX_KIND_END=ArgumentKind, |
| STATEMENT_KIND_BEGIN = VariableKind, |
| STATEMENT_KIND_END = ArgumentKind, |
| InitializerKind, |
| INITIALIZER_KIND_BEGIN=InitializerKind, |
| INITIALIZER_KIND_END=InitializerKind |
| }; |
| |
| LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) { |
| switch (K) { |
| case VariableKind: return "construct into local variable"; |
| case NewAllocatorKind: return "construct into new-allocator"; |
| case ReturnKind: return "construct into return address"; |
| case MaterializationKind: return "materialize temporary"; |
| case TemporaryDestructorKind: return "destroy temporary"; |
| case ElidedDestructorKind: return "elide destructor"; |
| case ElidableConstructorKind: return "elide constructor"; |
| case ArgumentKind: return "construct into argument"; |
| case InitializerKind: return "construct into member variable"; |
| }; |
| llvm_unreachable("Unknown ItemKind"); |
| } |
| |
| private: |
| const void *const Data; |
| const ItemKind Kind; |
| const unsigned Index = 0; |
| |
| bool hasStatement() const { |
| return Kind >= STATEMENT_KIND_BEGIN && |
| Kind <= STATEMENT_KIND_END; |
| } |
| |
| bool hasIndex() const { |
| return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN && |
| Kind >= STATEMENT_WITH_INDEX_KIND_END; |
| } |
| |
| bool hasInitializer() const { |
| return Kind >= INITIALIZER_KIND_BEGIN && |
| Kind <= INITIALIZER_KIND_END; |
| } |
| |
| public: |
| // ConstructionContextItem should be simple enough so that it was easy to |
| // re-construct it from the AST node it captures. For that reason we provide |
| // simple implicit conversions from all sorts of supported AST nodes. |
| ConstructionContextItem(const DeclStmt *DS) |
| : Data(DS), Kind(VariableKind) {} |
| |
| ConstructionContextItem(const CXXNewExpr *NE) |
| : Data(NE), Kind(NewAllocatorKind) {} |
| |
| ConstructionContextItem(const ReturnStmt *RS) |
| : Data(RS), Kind(ReturnKind) {} |
| |
| ConstructionContextItem(const MaterializeTemporaryExpr *MTE) |
| : Data(MTE), Kind(MaterializationKind) {} |
| |
| ConstructionContextItem(const CXXBindTemporaryExpr *BTE, |
| bool IsElided = false) |
| : Data(BTE), |
| Kind(IsElided ? ElidedDestructorKind : TemporaryDestructorKind) {} |
| |
| ConstructionContextItem(const CXXConstructExpr *CE) |
| : Data(CE), Kind(ElidableConstructorKind) {} |
| |
| ConstructionContextItem(const CallExpr *CE, unsigned Index) |
| : Data(CE), Kind(ArgumentKind), Index(Index) {} |
| |
| ConstructionContextItem(const CXXConstructExpr *CE, unsigned Index) |
| : Data(CE), Kind(ArgumentKind), Index(Index) {} |
| |
| ConstructionContextItem(const ObjCMessageExpr *ME, unsigned Index) |
| : Data(ME), Kind(ArgumentKind), Index(Index) {} |
| |
| // A polymorphic version of the previous calls with dynamic type check. |
| ConstructionContextItem(const Expr *E, unsigned Index) |
| : Data(E), Kind(ArgumentKind), Index(Index) { |
| assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) || |
| isa<ObjCMessageExpr>(E)); |
| } |
| |
| ConstructionContextItem(const CXXCtorInitializer *Init) |
| : Data(Init), Kind(InitializerKind), Index(0) {} |
| |
| ItemKind getKind() const { return Kind; } |
| |
| LLVM_DUMP_METHOD StringRef getKindAsString() const { |
| return getKindAsString(getKind()); |
| } |
| |
| /// The construction site - the statement that triggered the construction |
| /// for one of its parts. For instance, stack variable declaration statement |
| /// triggers construction of itself or its elements if it's an array, |
| /// new-expression triggers construction of the newly allocated object(s). |
| const Stmt *getStmt() const { |
| assert(hasStatement()); |
| return static_cast<const Stmt *>(Data); |
| } |
| |
| const Stmt *getStmtOrNull() const { |
| return hasStatement() ? getStmt() : nullptr; |
| } |
| |
| /// The construction site is not necessarily a statement. It may also be a |
| /// CXXCtorInitializer, which means that a member variable is being |
| /// constructed during initialization of the object that contains it. |
| const CXXCtorInitializer *getCXXCtorInitializer() const { |
| assert(hasInitializer()); |
| return static_cast<const CXXCtorInitializer *>(Data); |
| } |
| |
| /// If a single trigger statement triggers multiple constructors, they are |
| /// usually being enumerated. This covers function argument constructors |
| /// triggered by a call-expression and items in an initializer list triggered |
| /// by an init-list-expression. |
| unsigned getIndex() const { |
| // This is a fairly specific request. Let's make sure the user knows |
| // what he's doing. |
| assert(hasIndex()); |
| return Index; |
| } |
| |
| void Profile(llvm::FoldingSetNodeID &ID) const { |
| ID.AddPointer(Data); |
| ID.AddInteger(Kind); |
| ID.AddInteger(Index); |
| } |
| |
| bool operator==(const ConstructionContextItem &Other) const { |
| // For most kinds the Index comparison is trivially true, but |
| // checking kind separately doesn't seem to be less expensive |
| // than checking Index. Same in operator<(). |
| return std::make_tuple(Data, Kind, Index) == |
| std::make_tuple(Other.Data, Other.Kind, Other.Index); |
| } |
| |
| bool operator<(const ConstructionContextItem &Other) const { |
| return std::make_tuple(Data, Kind, Index) < |
| std::make_tuple(Other.Data, Other.Kind, Other.Index); |
| } |
| }; |
| |
| /// Construction context can be seen as a linked list of multiple layers. |
| /// Sometimes a single trigger is not enough to describe the construction |
| /// site. That's what causing us to have a chain of "partial" construction |
| /// context layers. Some examples: |
| /// - A constructor within in an aggregate initializer list within a variable |
| /// would have a construction context of the initializer list with |
| /// the parent construction context of a variable. |
| /// - A constructor for a temporary that needs to be both destroyed |
| /// and materialized into an elidable copy constructor would have a |
| /// construction context of a CXXBindTemporaryExpr with the parent |
| /// construction context of a MaterializeTemproraryExpr. |
| /// Not all of these are currently supported. |
| /// Layers are created gradually while traversing the AST, and layers that |
| /// represent the outmost AST nodes are built first, while the node that |
| /// immediately contains the constructor would be built last and capture the |
| /// previous layers as its parents. Construction context captures the last layer |
| /// (which has links to the previous layers) and classifies the seemingly |
| /// arbitrary chain of layers into one of the possible ways of constructing |
| /// an object in C++ for user-friendly experience. |
| class ConstructionContextLayer { |
| const ConstructionContextLayer *Parent = nullptr; |
| ConstructionContextItem Item; |
| |
| ConstructionContextLayer(ConstructionContextItem Item, |
| const ConstructionContextLayer *Parent) |
| : Parent(Parent), Item(Item) {} |
| |
| public: |
| static const ConstructionContextLayer * |
| create(BumpVectorContext &C, const ConstructionContextItem &Item, |
| const ConstructionContextLayer *Parent = nullptr); |
| |
| const ConstructionContextItem &getItem() const { return Item; } |
| const ConstructionContextLayer *getParent() const { return Parent; } |
| bool isLast() const { return !Parent; } |
| |
| /// See if Other is a proper initial segment of this construction context |
| /// in terms of the parent chain - i.e. a few first parents coincide and |
| /// then the other context terminates but our context goes further - i.e., |
| /// we are providing the same context that the other context provides, |
| /// and a bit more above that. |
| bool isStrictlyMoreSpecificThan(const ConstructionContextLayer *Other) const; |
| }; |
| |
| |
| /// ConstructionContext's subclasses describe different ways of constructing |
| /// an object in C++. The context re-captures the essential parent AST nodes |
| /// of the CXXConstructExpr it is assigned to and presents these nodes |
| /// through easy-to-understand accessor methods. |
| class ConstructionContext { |
| public: |
| enum Kind { |
| SimpleVariableKind, |
| CXX17ElidedCopyVariableKind, |
| VARIABLE_BEGIN = SimpleVariableKind, |
| VARIABLE_END = CXX17ElidedCopyVariableKind, |
| SimpleConstructorInitializerKind, |
| CXX17ElidedCopyConstructorInitializerKind, |
| INITIALIZER_BEGIN = SimpleConstructorInitializerKind, |
| INITIALIZER_END = CXX17ElidedCopyConstructorInitializerKind, |
| NewAllocatedObjectKind, |
| SimpleTemporaryObjectKind, |
| ElidedTemporaryObjectKind, |
| TEMPORARY_BEGIN = SimpleTemporaryObjectKind, |
| TEMPORARY_END = ElidedTemporaryObjectKind, |
| SimpleReturnedValueKind, |
| CXX17ElidedCopyReturnedValueKind, |
| RETURNED_VALUE_BEGIN = SimpleReturnedValueKind, |
| RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind, |
| ArgumentKind |
| }; |
| |
| protected: |
| Kind K; |
| |
| // Do not make public! These need to only be constructed |
| // via createFromLayers(). |
| explicit ConstructionContext(Kind K) : K(K) {} |
| |
| private: |
| // A helper function for constructing an instance into a bump vector context. |
| template <typename T, typename... ArgTypes> |
| static T *create(BumpVectorContext &C, ArgTypes... Args) { |
| auto *CC = C.getAllocator().Allocate<T>(); |
| return new (CC) T(Args...); |
| } |
| |
| // A sub-routine of createFromLayers() that deals with temporary objects |
| // that need to be materialized. The BTE argument is for the situation when |
| // the object also needs to be bound for destruction. |
| static const ConstructionContext *createMaterializedTemporaryFromLayers( |
| BumpVectorContext &C, const MaterializeTemporaryExpr *MTE, |
| const CXXBindTemporaryExpr *BTE, |
| const ConstructionContextLayer *ParentLayer); |
| |
| // A sub-routine of createFromLayers() that deals with temporary objects |
| // that need to be bound for destruction. Automatically finds out if the |
| // object also needs to be materialized and delegates to |
| // createMaterializedTemporaryFromLayers() if necessary. |
| static const ConstructionContext * |
| createBoundTemporaryFromLayers( |
| BumpVectorContext &C, const CXXBindTemporaryExpr *BTE, |
| const ConstructionContextLayer *ParentLayer); |
| |
| public: |
| /// Consume the construction context layer, together with its parent layers, |
| /// and wrap it up into a complete construction context. May return null |
| /// if layers do not form any supported construction context. |
| static const ConstructionContext * |
| createFromLayers(BumpVectorContext &C, |
| const ConstructionContextLayer *TopLayer); |
| |
| Kind getKind() const { return K; } |
| }; |
| |
| /// An abstract base class for local variable constructors. |
| class VariableConstructionContext : public ConstructionContext { |
| const DeclStmt *DS; |
| |
| protected: |
| VariableConstructionContext(ConstructionContext::Kind K, const DeclStmt *DS) |
| : ConstructionContext(K), DS(DS) { |
| assert(classof(this)); |
| assert(DS); |
| } |
| |
| public: |
| const DeclStmt *getDeclStmt() const { return DS; } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() >= VARIABLE_BEGIN && |
| CC->getKind() <= VARIABLE_END; |
| } |
| }; |
| |
| /// Represents construction into a simple local variable, eg. T var(123);. |
| /// If a variable has an initializer, eg. T var = makeT();, then the final |
| /// elidable copy-constructor from makeT() into var would also be a simple |
| /// variable constructor handled by this class. |
| class SimpleVariableConstructionContext : public VariableConstructionContext { |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit SimpleVariableConstructionContext(const DeclStmt *DS) |
| : VariableConstructionContext(ConstructionContext::SimpleVariableKind, |
| DS) {} |
| |
| public: |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == SimpleVariableKind; |
| } |
| }; |
| |
| /// Represents construction into a simple variable with an initializer syntax, |
| /// with a single constructor, eg. T var = makeT();. Such construction context |
| /// may only appear in C++17 because previously it was split into a temporary |
| /// object constructor and an elidable simple variable copy-constructor and |
| /// we were producing separate construction contexts for these constructors. |
| /// In C++17 we have a single construction context that combines both. |
| /// Note that if the object has trivial destructor, then this code is |
| /// indistinguishable from a simple variable constructor on the AST level; |
| /// in this case we provide a simple variable construction context. |
| class CXX17ElidedCopyVariableConstructionContext |
| : public VariableConstructionContext { |
| const CXXBindTemporaryExpr *BTE; |
| |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit CXX17ElidedCopyVariableConstructionContext( |
| const DeclStmt *DS, const CXXBindTemporaryExpr *BTE) |
| : VariableConstructionContext(CXX17ElidedCopyVariableKind, DS), BTE(BTE) { |
| assert(BTE); |
| } |
| |
| public: |
| const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == CXX17ElidedCopyVariableKind; |
| } |
| }; |
| |
| // An abstract base class for constructor-initializer-based constructors. |
| class ConstructorInitializerConstructionContext : public ConstructionContext { |
| const CXXCtorInitializer *I; |
| |
| protected: |
| explicit ConstructorInitializerConstructionContext( |
| ConstructionContext::Kind K, const CXXCtorInitializer *I) |
| : ConstructionContext(K), I(I) { |
| assert(classof(this)); |
| assert(I); |
| } |
| |
| public: |
| const CXXCtorInitializer *getCXXCtorInitializer() const { return I; } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() >= INITIALIZER_BEGIN && |
| CC->getKind() <= INITIALIZER_END; |
| } |
| }; |
| |
| /// Represents construction into a field or a base class within a bigger object |
| /// via a constructor initializer, eg. T(): field(123) { ... }. |
| class SimpleConstructorInitializerConstructionContext |
| : public ConstructorInitializerConstructionContext { |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit SimpleConstructorInitializerConstructionContext( |
| const CXXCtorInitializer *I) |
| : ConstructorInitializerConstructionContext( |
| ConstructionContext::SimpleConstructorInitializerKind, I) {} |
| |
| public: |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == SimpleConstructorInitializerKind; |
| } |
| }; |
| |
| /// Represents construction into a field or a base class within a bigger object |
| /// via a constructor initializer, with a single constructor, eg. |
| /// T(): field(Field(123)) { ... }. Such construction context may only appear |
| /// in C++17 because previously it was split into a temporary object constructor |
| /// and an elidable simple constructor-initializer copy-constructor and we were |
| /// producing separate construction contexts for these constructors. In C++17 |
| /// we have a single construction context that combines both. Note that if the |
| /// object has trivial destructor, then this code is indistinguishable from |
| /// a simple constructor-initializer constructor on the AST level; in this case |
| /// we provide a simple constructor-initializer construction context. |
| class CXX17ElidedCopyConstructorInitializerConstructionContext |
| : public ConstructorInitializerConstructionContext { |
| const CXXBindTemporaryExpr *BTE; |
| |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit CXX17ElidedCopyConstructorInitializerConstructionContext( |
| const CXXCtorInitializer *I, const CXXBindTemporaryExpr *BTE) |
| : ConstructorInitializerConstructionContext( |
| CXX17ElidedCopyConstructorInitializerKind, I), |
| BTE(BTE) { |
| assert(BTE); |
| } |
| |
| public: |
| const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == CXX17ElidedCopyConstructorInitializerKind; |
| } |
| }; |
| |
| /// Represents immediate initialization of memory allocated by operator new, |
| /// eg. new T(123);. |
| class NewAllocatedObjectConstructionContext : public ConstructionContext { |
| const CXXNewExpr *NE; |
| |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit NewAllocatedObjectConstructionContext(const CXXNewExpr *NE) |
| : ConstructionContext(ConstructionContext::NewAllocatedObjectKind), |
| NE(NE) { |
| assert(NE); |
| } |
| |
| public: |
| const CXXNewExpr *getCXXNewExpr() const { return NE; } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == NewAllocatedObjectKind; |
| } |
| }; |
| |
| /// Represents a temporary object, eg. T(123), that does not immediately cross |
| /// function boundaries "by value"; constructors that construct function |
| /// value-type arguments or values that are immediately returned from the |
| /// function that returns a value receive separate construction context kinds. |
| class TemporaryObjectConstructionContext : public ConstructionContext { |
| const CXXBindTemporaryExpr *BTE; |
| const MaterializeTemporaryExpr *MTE; |
| |
| protected: |
| explicit TemporaryObjectConstructionContext( |
| ConstructionContext::Kind K, const CXXBindTemporaryExpr *BTE, |
| const MaterializeTemporaryExpr *MTE) |
| : ConstructionContext(K), BTE(BTE), MTE(MTE) { |
| // Both BTE and MTE can be null here, all combinations possible. |
| // Even though for now at least one should be non-null, we simply haven't |
| // implemented the other case yet (this would be a temporary in the middle |
| // of nowhere that doesn't have a non-trivial destructor). |
| } |
| |
| public: |
| /// CXXBindTemporaryExpr here is non-null as long as the temporary has |
| /// a non-trivial destructor. |
| const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { |
| return BTE; |
| } |
| |
| /// MaterializeTemporaryExpr is non-null as long as the temporary is actually |
| /// used after construction, eg. by binding to a reference (lifetime |
| /// extension), accessing a field, calling a method, or passing it into |
| /// a function (an elidable copy or move constructor would be a common |
| /// example) by reference. |
| const MaterializeTemporaryExpr *getMaterializedTemporaryExpr() const { |
| return MTE; |
| } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() >= TEMPORARY_BEGIN && CC->getKind() <= TEMPORARY_END; |
| } |
| }; |
| |
| /// Represents a temporary object that is not constructed for the purpose of |
| /// being immediately copied/moved by an elidable copy/move-constructor. |
| /// This includes temporary objects "in the middle of nowhere" like T(123) and |
| /// lifetime-extended temporaries. |
| class SimpleTemporaryObjectConstructionContext |
| : public TemporaryObjectConstructionContext { |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit SimpleTemporaryObjectConstructionContext( |
| const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE) |
| : TemporaryObjectConstructionContext( |
| ConstructionContext::SimpleTemporaryObjectKind, BTE, MTE) {} |
| |
| public: |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == SimpleTemporaryObjectKind; |
| } |
| }; |
| |
| /// Represents a temporary object that is constructed for the sole purpose |
| /// of being immediately copied by an elidable copy/move constructor. |
| /// For example, T t = T(123); includes a temporary T(123) that is immediately |
| /// copied to variable t. In such cases the elidable copy can (but not |
| /// necessarily should) be omitted ("elided") accodring to the rules of the |
| /// language; the constructor would then construct variable t directly. |
| /// This construction context contains information of the elidable constructor |
| /// and its respective construction context. |
| class ElidedTemporaryObjectConstructionContext |
| : public TemporaryObjectConstructionContext { |
| const CXXConstructExpr *ElidedCE; |
| const ConstructionContext *ElidedCC; |
| |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit ElidedTemporaryObjectConstructionContext( |
| const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE, |
| const CXXConstructExpr *ElidedCE, const ConstructionContext *ElidedCC) |
| : TemporaryObjectConstructionContext( |
| ConstructionContext::ElidedTemporaryObjectKind, BTE, MTE), |
| ElidedCE(ElidedCE), ElidedCC(ElidedCC) { |
| // Elided constructor and its context should be either both specified |
| // or both unspecified. In the former case, the constructor must be |
| // elidable. |
| assert(ElidedCE && ElidedCE->isElidable() && ElidedCC); |
| } |
| |
| public: |
| const CXXConstructExpr *getConstructorAfterElision() const { |
| return ElidedCE; |
| } |
| |
| const ConstructionContext *getConstructionContextAfterElision() const { |
| return ElidedCC; |
| } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == ElidedTemporaryObjectKind; |
| } |
| }; |
| |
| class ReturnedValueConstructionContext : public ConstructionContext { |
| const ReturnStmt *RS; |
| |
| protected: |
| explicit ReturnedValueConstructionContext(ConstructionContext::Kind K, |
| const ReturnStmt *RS) |
| : ConstructionContext(K), RS(RS) { |
| assert(classof(this)); |
| assert(RS); |
| } |
| |
| public: |
| const ReturnStmt *getReturnStmt() const { return RS; } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() >= RETURNED_VALUE_BEGIN && |
| CC->getKind() <= RETURNED_VALUE_END; |
| } |
| }; |
| |
| /// Represents a temporary object that is being immediately returned from a |
| /// function by value, eg. return t; or return T(123);. In this case there is |
| /// always going to be a constructor at the return site. However, the usual |
| /// temporary-related bureaucracy (CXXBindTemporaryExpr, |
| /// MaterializeTemporaryExpr) is normally located in the caller function's AST. |
| class SimpleReturnedValueConstructionContext |
| : public ReturnedValueConstructionContext { |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit SimpleReturnedValueConstructionContext(const ReturnStmt *RS) |
| : ReturnedValueConstructionContext( |
| ConstructionContext::SimpleReturnedValueKind, RS) {} |
| |
| public: |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == SimpleReturnedValueKind; |
| } |
| }; |
| |
| /// Represents a temporary object that is being immediately returned from a |
| /// function by value, eg. return t; or return T(123); in C++17. |
| /// In C++17 there is not going to be an elidable copy constructor at the |
| /// return site. However, the usual temporary-related bureaucracy (CXXBindTemporaryExpr, |
| /// MaterializeTemporaryExpr) is normally located in the caller function's AST. |
| /// Note that if the object has trivial destructor, then this code is |
| /// indistinguishable from a simple returned value constructor on the AST level; |
| /// in this case we provide a simple returned value construction context. |
| class CXX17ElidedCopyReturnedValueConstructionContext |
| : public ReturnedValueConstructionContext { |
| const CXXBindTemporaryExpr *BTE; |
| |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit CXX17ElidedCopyReturnedValueConstructionContext( |
| const ReturnStmt *RS, const CXXBindTemporaryExpr *BTE) |
| : ReturnedValueConstructionContext( |
| ConstructionContext::CXX17ElidedCopyReturnedValueKind, RS), |
| BTE(BTE) { |
| assert(BTE); |
| } |
| |
| public: |
| const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == CXX17ElidedCopyReturnedValueKind; |
| } |
| }; |
| |
| class ArgumentConstructionContext : public ConstructionContext { |
| const Expr *CE; // The call of which the context is an argument. |
| unsigned Index; // Which argument we're constructing. |
| const CXXBindTemporaryExpr *BTE; // Whether the object needs to be destroyed. |
| |
| friend class ConstructionContext; // Allows to create<>() itself. |
| |
| explicit ArgumentConstructionContext(const Expr *CE, unsigned Index, |
| const CXXBindTemporaryExpr *BTE) |
| : ConstructionContext(ArgumentKind), CE(CE), |
| Index(Index), BTE(BTE) { |
| assert(isa<CallExpr>(CE) || isa<CXXConstructExpr>(CE) || |
| isa<ObjCMessageExpr>(CE)); |
| // BTE is optional. |
| } |
| |
| public: |
| const Expr *getCallLikeExpr() const { return CE; } |
| unsigned getIndex() const { return Index; } |
| const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } |
| |
| static bool classof(const ConstructionContext *CC) { |
| return CC->getKind() == ArgumentKind; |
| } |
| }; |
| |
| } // end namespace clang |
| |
| #endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H |