aboutsummaryrefslogtreecommitdiff
path: root/include/clang/Analysis/ConstructionContext.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/Analysis/ConstructionContext.h')
-rw-r--r--include/clang/Analysis/ConstructionContext.h474
1 files changed, 474 insertions, 0 deletions
diff --git a/include/clang/Analysis/ConstructionContext.h b/include/clang/Analysis/ConstructionContext.h
new file mode 100644
index 000000000000..40cb0e7e5dda
--- /dev/null
+++ b/include/clang/Analysis/ConstructionContext.h
@@ -0,0 +1,474 @@
+//===- 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 {
+
+/// Construction context is a linked list of multiple layers. 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 {
+public:
+ typedef llvm::PointerUnion<Stmt *, CXXCtorInitializer *> TriggerTy;
+
+private:
+ /// 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).
+ TriggerTy Trigger;
+
+ /// Sometimes a single trigger is not enough to describe the construction
+ /// site. In this case we'd 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.
+ const ConstructionContextLayer *Parent = nullptr;
+
+ ConstructionContextLayer(TriggerTy Trigger,
+ const ConstructionContextLayer *Parent)
+ : Trigger(Trigger), Parent(Parent) {}
+
+public:
+ static const ConstructionContextLayer *
+ create(BumpVectorContext &C, TriggerTy Trigger,
+ const ConstructionContextLayer *Parent = nullptr);
+
+ const ConstructionContextLayer *getParent() const { return Parent; }
+ bool isLast() const { return !Parent; }
+
+ const Stmt *getTriggerStmt() const {
+ return Trigger.dyn_cast<Stmt *>();
+ }
+
+ const CXXCtorInitializer *getTriggerInit() const {
+ return Trigger.dyn_cast<CXXCtorInitializer *>();
+ }
+
+ /// Returns true if these layers are equal as individual layers, even if
+ /// their parents are different.
+ bool isSameLayer(const ConstructionContextLayer *Other) const {
+ assert(Other);
+ return (Trigger == Other->Trigger);
+ }
+
+ /// 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
+ };
+
+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...);
+ }
+
+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;
+ }
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H