diff options
Diffstat (limited to 'include/clang/Sema/ScopeInfo.h')
-rw-r--r-- | include/clang/Sema/ScopeInfo.h | 858 |
1 files changed, 0 insertions, 858 deletions
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h deleted file mode 100644 index d13667e..0000000 --- a/include/clang/Sema/ScopeInfo.h +++ /dev/null @@ -1,858 +0,0 @@ -//===--- ScopeInfo.h - Information about a semantic context -----*- 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 FunctionScopeInfo and its subclasses, which contain -// information about a single function, block, lambda, or method body. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SEMA_SCOPEINFO_H -#define LLVM_CLANG_SEMA_SCOPEINFO_H - -#include "clang/AST/Expr.h" -#include "clang/AST/Type.h" -#include "clang/Basic/CapturedStmt.h" -#include "clang/Basic/PartialDiagnostic.h" -#include "clang/Sema/Ownership.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/SmallVector.h" -#include <algorithm> - -namespace clang { - -class Decl; -class BlockDecl; -class CapturedDecl; -class CXXMethodDecl; -class FieldDecl; -class ObjCPropertyDecl; -class IdentifierInfo; -class ImplicitParamDecl; -class LabelDecl; -class ReturnStmt; -class Scope; -class SwitchStmt; -class TemplateTypeParmDecl; -class TemplateParameterList; -class VarDecl; -class ObjCIvarRefExpr; -class ObjCPropertyRefExpr; -class ObjCMessageExpr; - -namespace sema { - -/// \brief Contains information about the compound statement currently being -/// parsed. -class CompoundScopeInfo { -public: - CompoundScopeInfo() - : HasEmptyLoopBodies(false) { } - - /// \brief Whether this compound stamement contains `for' or `while' loops - /// with empty bodies. - bool HasEmptyLoopBodies; - - void setHasEmptyLoopBodies() { - HasEmptyLoopBodies = true; - } -}; - -class PossiblyUnreachableDiag { -public: - PartialDiagnostic PD; - SourceLocation Loc; - const Stmt *stmt; - - PossiblyUnreachableDiag(const PartialDiagnostic &PD, SourceLocation Loc, - const Stmt *stmt) - : PD(PD), Loc(Loc), stmt(stmt) {} -}; - -/// \brief Retains information about a function, method, or block that is -/// currently being parsed. -class FunctionScopeInfo { -protected: - enum ScopeKind { - SK_Function, - SK_Block, - SK_Lambda, - SK_CapturedRegion - }; - -public: - /// \brief What kind of scope we are describing. - /// - ScopeKind Kind : 3; - - /// \brief Whether this function contains a VLA, \@try, try, C++ - /// initializer, or anything else that can't be jumped past. - bool HasBranchProtectedScope : 1; - - /// \brief Whether this function contains any switches or direct gotos. - bool HasBranchIntoScope : 1; - - /// \brief Whether this function contains any indirect gotos. - bool HasIndirectGoto : 1; - - /// \brief Whether a statement was dropped because it was invalid. - bool HasDroppedStmt : 1; - - /// A flag that is set when parsing a method that must call super's - /// implementation, such as \c -dealloc, \c -finalize, or any method marked - /// with \c __attribute__((objc_requires_super)). - bool ObjCShouldCallSuper : 1; - - /// True when this is a method marked as a designated initializer. - bool ObjCIsDesignatedInit : 1; - /// This starts true for a method marked as designated initializer and will - /// be set to false if there is an invocation to a designated initializer of - /// the super class. - bool ObjCWarnForNoDesignatedInitChain : 1; - - /// True when this is an initializer method not marked as a designated - /// initializer within a class that has at least one initializer marked as a - /// designated initializer. - bool ObjCIsSecondaryInit : 1; - /// This starts true for a secondary initializer method and will be set to - /// false if there is an invocation of an initializer on 'self'. - bool ObjCWarnForNoInitDelegation : 1; - - /// First 'return' statement in the current function. - SourceLocation FirstReturnLoc; - - /// First C++ 'try' statement in the current function. - SourceLocation FirstCXXTryLoc; - - /// First SEH '__try' statement in the current function. - SourceLocation FirstSEHTryLoc; - - /// \brief Used to determine if errors occurred in this function or block. - DiagnosticErrorTrap ErrorTrap; - - /// SwitchStack - This is the current set of active switch statements in the - /// block. - SmallVector<SwitchStmt*, 8> SwitchStack; - - /// \brief The list of return statements that occur within the function or - /// block, if there is any chance of applying the named return value - /// optimization, or if we need to infer a return type. - SmallVector<ReturnStmt*, 4> Returns; - - /// \brief The promise object for this coroutine, if any. - VarDecl *CoroutinePromise; - - /// \brief The list of coroutine control flow constructs (co_await, co_yield, - /// co_return) that occur within the function or block. Empty if and only if - /// this function or block is not (yet known to be) a coroutine. - SmallVector<Stmt*, 4> CoroutineStmts; - - /// \brief The stack of currently active compound stamement scopes in the - /// function. - SmallVector<CompoundScopeInfo, 4> CompoundScopes; - - /// \brief A list of PartialDiagnostics created but delayed within the - /// current function scope. These diagnostics are vetted for reachability - /// prior to being emitted. - SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags; - - /// \brief A list of parameters which have the nonnull attribute and are - /// modified in the function. - llvm::SmallPtrSet<const ParmVarDecl*, 8> ModifiedNonNullParams; - -public: - /// Represents a simple identification of a weak object. - /// - /// Part of the implementation of -Wrepeated-use-of-weak. - /// - /// This is used to determine if two weak accesses refer to the same object. - /// Here are some examples of how various accesses are "profiled": - /// - /// Access Expression | "Base" Decl | "Property" Decl - /// :---------------: | :-----------------: | :------------------------------: - /// self.property | self (VarDecl) | property (ObjCPropertyDecl) - /// self.implicitProp | self (VarDecl) | -implicitProp (ObjCMethodDecl) - /// self->ivar.prop | ivar (ObjCIvarDecl) | prop (ObjCPropertyDecl) - /// cxxObj.obj.prop | obj (FieldDecl) | prop (ObjCPropertyDecl) - /// [self foo].prop | 0 (unknown) | prop (ObjCPropertyDecl) - /// self.prop1.prop2 | prop1 (ObjCPropertyDecl) | prop2 (ObjCPropertyDecl) - /// MyClass.prop | MyClass (ObjCInterfaceDecl) | -prop (ObjCMethodDecl) - /// weakVar | 0 (known) | weakVar (VarDecl) - /// self->weakIvar | self (VarDecl) | weakIvar (ObjCIvarDecl) - /// - /// Objects are identified with only two Decls to make it reasonably fast to - /// compare them. - class WeakObjectProfileTy { - /// The base object decl, as described in the class documentation. - /// - /// The extra flag is "true" if the Base and Property are enough to uniquely - /// identify the object in memory. - /// - /// \sa isExactProfile() - typedef llvm::PointerIntPair<const NamedDecl *, 1, bool> BaseInfoTy; - BaseInfoTy Base; - - /// The "property" decl, as described in the class documentation. - /// - /// Note that this may not actually be an ObjCPropertyDecl, e.g. in the - /// case of "implicit" properties (regular methods accessed via dot syntax). - const NamedDecl *Property; - - /// Used to find the proper base profile for a given base expression. - static BaseInfoTy getBaseInfo(const Expr *BaseE); - - inline WeakObjectProfileTy(); - static inline WeakObjectProfileTy getSentinel(); - - public: - WeakObjectProfileTy(const ObjCPropertyRefExpr *RE); - WeakObjectProfileTy(const Expr *Base, const ObjCPropertyDecl *Property); - WeakObjectProfileTy(const DeclRefExpr *RE); - WeakObjectProfileTy(const ObjCIvarRefExpr *RE); - - const NamedDecl *getBase() const { return Base.getPointer(); } - const NamedDecl *getProperty() const { return Property; } - - /// Returns true if the object base specifies a known object in memory, - /// rather than, say, an instance variable or property of another object. - /// - /// Note that this ignores the effects of aliasing; that is, \c foo.bar is - /// considered an exact profile if \c foo is a local variable, even if - /// another variable \c foo2 refers to the same object as \c foo. - /// - /// For increased precision, accesses with base variables that are - /// properties or ivars of 'self' (e.g. self.prop1.prop2) are considered to - /// be exact, though this is not true for arbitrary variables - /// (foo.prop1.prop2). - bool isExactProfile() const { - return Base.getInt(); - } - - bool operator==(const WeakObjectProfileTy &Other) const { - return Base == Other.Base && Property == Other.Property; - } - - // For use in DenseMap. - // We can't specialize the usual llvm::DenseMapInfo at the end of the file - // because by that point the DenseMap in FunctionScopeInfo has already been - // instantiated. - class DenseMapInfo { - public: - static inline WeakObjectProfileTy getEmptyKey() { - return WeakObjectProfileTy(); - } - static inline WeakObjectProfileTy getTombstoneKey() { - return WeakObjectProfileTy::getSentinel(); - } - - static unsigned getHashValue(const WeakObjectProfileTy &Val) { - typedef std::pair<BaseInfoTy, const NamedDecl *> Pair; - return llvm::DenseMapInfo<Pair>::getHashValue(Pair(Val.Base, - Val.Property)); - } - - static bool isEqual(const WeakObjectProfileTy &LHS, - const WeakObjectProfileTy &RHS) { - return LHS == RHS; - } - }; - }; - - /// Represents a single use of a weak object. - /// - /// Stores both the expression and whether the access is potentially unsafe - /// (i.e. it could potentially be warned about). - /// - /// Part of the implementation of -Wrepeated-use-of-weak. - class WeakUseTy { - llvm::PointerIntPair<const Expr *, 1, bool> Rep; - public: - WeakUseTy(const Expr *Use, bool IsRead) : Rep(Use, IsRead) {} - - const Expr *getUseExpr() const { return Rep.getPointer(); } - bool isUnsafe() const { return Rep.getInt(); } - void markSafe() { Rep.setInt(false); } - - bool operator==(const WeakUseTy &Other) const { - return Rep == Other.Rep; - } - }; - - /// Used to collect uses of a particular weak object in a function body. - /// - /// Part of the implementation of -Wrepeated-use-of-weak. - typedef SmallVector<WeakUseTy, 4> WeakUseVector; - - /// Used to collect all uses of weak objects in a function body. - /// - /// Part of the implementation of -Wrepeated-use-of-weak. - typedef llvm::SmallDenseMap<WeakObjectProfileTy, WeakUseVector, 8, - WeakObjectProfileTy::DenseMapInfo> - WeakObjectUseMap; - -private: - /// Used to collect all uses of weak objects in this function body. - /// - /// Part of the implementation of -Wrepeated-use-of-weak. - WeakObjectUseMap WeakObjectUses; - -protected: - FunctionScopeInfo(const FunctionScopeInfo&) = default; - -public: - /// Record that a weak object was accessed. - /// - /// Part of the implementation of -Wrepeated-use-of-weak. - template <typename ExprT> - inline void recordUseOfWeak(const ExprT *E, bool IsRead = true); - - void recordUseOfWeak(const ObjCMessageExpr *Msg, - const ObjCPropertyDecl *Prop); - - /// Record that a given expression is a "safe" access of a weak object (e.g. - /// assigning it to a strong variable.) - /// - /// Part of the implementation of -Wrepeated-use-of-weak. - void markSafeWeakUse(const Expr *E); - - const WeakObjectUseMap &getWeakObjectUses() const { - return WeakObjectUses; - } - - void setHasBranchIntoScope() { - HasBranchIntoScope = true; - } - - void setHasBranchProtectedScope() { - HasBranchProtectedScope = true; - } - - void setHasIndirectGoto() { - HasIndirectGoto = true; - } - - void setHasDroppedStmt() { - HasDroppedStmt = true; - } - - void setHasCXXTry(SourceLocation TryLoc) { - setHasBranchProtectedScope(); - FirstCXXTryLoc = TryLoc; - } - - void setHasSEHTry(SourceLocation TryLoc) { - setHasBranchProtectedScope(); - FirstSEHTryLoc = TryLoc; - } - - bool NeedsScopeChecking() const { - return !HasDroppedStmt && - (HasIndirectGoto || - (HasBranchProtectedScope && HasBranchIntoScope)); - } - - FunctionScopeInfo(DiagnosticsEngine &Diag) - : Kind(SK_Function), - HasBranchProtectedScope(false), - HasBranchIntoScope(false), - HasIndirectGoto(false), - HasDroppedStmt(false), - ObjCShouldCallSuper(false), - ObjCIsDesignatedInit(false), - ObjCWarnForNoDesignatedInitChain(false), - ObjCIsSecondaryInit(false), - ObjCWarnForNoInitDelegation(false), - ErrorTrap(Diag) { } - - virtual ~FunctionScopeInfo(); - - /// \brief Clear out the information in this function scope, making it - /// suitable for reuse. - void Clear(); -}; - -class CapturingScopeInfo : public FunctionScopeInfo { -protected: - CapturingScopeInfo(const CapturingScopeInfo&) = default; - -public: - enum ImplicitCaptureStyle { - ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block, - ImpCap_CapturedRegion - }; - - ImplicitCaptureStyle ImpCaptureStyle; - - class Capture { - // There are three categories of capture: capturing 'this', capturing - // local variables, and C++1y initialized captures (which can have an - // arbitrary initializer, and don't really capture in the traditional - // sense at all). - // - // There are three ways to capture a local variable: - // - capture by copy in the C++11 sense, - // - capture by reference in the C++11 sense, and - // - __block capture. - // Lambdas explicitly specify capture by copy or capture by reference. - // For blocks, __block capture applies to variables with that annotation, - // variables of reference type are captured by reference, and other - // variables are captured by copy. - enum CaptureKind { - Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_This - }; - - /// The variable being captured (if we are not capturing 'this') and whether - /// this is a nested capture. - llvm::PointerIntPair<VarDecl*, 1, bool> VarAndNested; - - /// Expression to initialize a field of the given type, and the kind of - /// capture (if this is a capture and not an init-capture). The expression - /// is only required if we are capturing ByVal and the variable's type has - /// a non-trivial copy constructor. - llvm::PointerIntPair<void *, 2, CaptureKind> InitExprAndCaptureKind; - - /// \brief The source location at which the first capture occurred. - SourceLocation Loc; - - /// \brief The location of the ellipsis that expands a parameter pack. - SourceLocation EllipsisLoc; - - /// \brief The type as it was captured, which is in effect the type of the - /// non-static data member that would hold the capture. - QualType CaptureType; - - public: - Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested, - SourceLocation Loc, SourceLocation EllipsisLoc, - QualType CaptureType, Expr *Cpy) - : VarAndNested(Var, IsNested), - InitExprAndCaptureKind(Cpy, Block ? Cap_Block : - ByRef ? Cap_ByRef : Cap_ByCopy), - Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {} - - enum IsThisCapture { ThisCapture }; - Capture(IsThisCapture, bool IsNested, SourceLocation Loc, - QualType CaptureType, Expr *Cpy) - : VarAndNested(nullptr, IsNested), - InitExprAndCaptureKind(Cpy, Cap_This), - Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {} - - bool isThisCapture() const { - return InitExprAndCaptureKind.getInt() == Cap_This; - } - bool isVariableCapture() const { - return InitExprAndCaptureKind.getInt() != Cap_This && !isVLATypeCapture(); - } - bool isCopyCapture() const { - return InitExprAndCaptureKind.getInt() == Cap_ByCopy && - !isVLATypeCapture(); - } - bool isReferenceCapture() const { - return InitExprAndCaptureKind.getInt() == Cap_ByRef; - } - bool isBlockCapture() const { - return InitExprAndCaptureKind.getInt() == Cap_Block; - } - bool isVLATypeCapture() const { - return InitExprAndCaptureKind.getInt() == Cap_ByCopy && - getVariable() == nullptr; - } - bool isNested() const { return VarAndNested.getInt(); } - - VarDecl *getVariable() const { - return VarAndNested.getPointer(); - } - - /// \brief Retrieve the location at which this variable was captured. - SourceLocation getLocation() const { return Loc; } - - /// \brief Retrieve the source location of the ellipsis, whose presence - /// indicates that the capture is a pack expansion. - SourceLocation getEllipsisLoc() const { return EllipsisLoc; } - - /// \brief Retrieve the capture type for this capture, which is effectively - /// the type of the non-static data member in the lambda/block structure - /// that would store this capture. - QualType getCaptureType() const { return CaptureType; } - - Expr *getInitExpr() const { - assert(!isVLATypeCapture() && "no init expression for type capture"); - return static_cast<Expr *>(InitExprAndCaptureKind.getPointer()); - } - }; - - CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style) - : FunctionScopeInfo(Diag), ImpCaptureStyle(Style), CXXThisCaptureIndex(0), - HasImplicitReturnType(false) - {} - - /// CaptureMap - A map of captured variables to (index+1) into Captures. - llvm::DenseMap<VarDecl*, unsigned> CaptureMap; - - /// CXXThisCaptureIndex - The (index+1) of the capture of 'this'; - /// zero if 'this' is not captured. - unsigned CXXThisCaptureIndex; - - /// Captures - The captures. - SmallVector<Capture, 4> Captures; - - /// \brief - Whether the target type of return statements in this context - /// is deduced (e.g. a lambda or block with omitted return type). - bool HasImplicitReturnType; - - /// ReturnType - The target type of return statements in this context, - /// or null if unknown. - QualType ReturnType; - - void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested, - SourceLocation Loc, SourceLocation EllipsisLoc, - QualType CaptureType, Expr *Cpy) { - Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, - EllipsisLoc, CaptureType, Cpy)); - CaptureMap[Var] = Captures.size(); - } - - void addVLATypeCapture(SourceLocation Loc, QualType CaptureType) { - Captures.push_back(Capture(/*Var*/ nullptr, /*isBlock*/ false, - /*isByref*/ false, /*isNested*/ false, Loc, - /*EllipsisLoc*/ SourceLocation(), CaptureType, - /*Cpy*/ nullptr)); - } - - void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType, - Expr *Cpy); - - /// \brief Determine whether the C++ 'this' is captured. - bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; } - - /// \brief Retrieve the capture of C++ 'this', if it has been captured. - Capture &getCXXThisCapture() { - assert(isCXXThisCaptured() && "this has not been captured"); - return Captures[CXXThisCaptureIndex - 1]; - } - - /// \brief Determine whether the given variable has been captured. - bool isCaptured(VarDecl *Var) const { - return CaptureMap.count(Var); - } - - /// \brief Determine whether the given variable-array type has been captured. - bool isVLATypeCaptured(const VariableArrayType *VAT) const; - - /// \brief Retrieve the capture of the given variable, if it has been - /// captured already. - Capture &getCapture(VarDecl *Var) { - assert(isCaptured(Var) && "Variable has not been captured"); - return Captures[CaptureMap[Var] - 1]; - } - - const Capture &getCapture(VarDecl *Var) const { - llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known - = CaptureMap.find(Var); - assert(Known != CaptureMap.end() && "Variable has not been captured"); - return Captures[Known->second - 1]; - } - - static bool classof(const FunctionScopeInfo *FSI) { - return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda - || FSI->Kind == SK_CapturedRegion; - } -}; - -/// \brief Retains information about a block that is currently being parsed. -class BlockScopeInfo final : public CapturingScopeInfo { -public: - BlockDecl *TheDecl; - - /// TheScope - This is the scope for the block itself, which contains - /// arguments etc. - Scope *TheScope; - - /// BlockType - The function type of the block, if one was given. - /// Its return type may be BuiltinType::Dependent. - QualType FunctionType; - - BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block) - : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block), - TheScope(BlockScope) - { - Kind = SK_Block; - } - - ~BlockScopeInfo() override; - - static bool classof(const FunctionScopeInfo *FSI) { - return FSI->Kind == SK_Block; - } -}; - -/// \brief Retains information about a captured region. -class CapturedRegionScopeInfo final : public CapturingScopeInfo { -public: - /// \brief The CapturedDecl for this statement. - CapturedDecl *TheCapturedDecl; - /// \brief The captured record type. - RecordDecl *TheRecordDecl; - /// \brief This is the enclosing scope of the captured region. - Scope *TheScope; - /// \brief The implicit parameter for the captured variables. - ImplicitParamDecl *ContextParam; - /// \brief The kind of captured region. - CapturedRegionKind CapRegionKind; - - CapturedRegionScopeInfo(DiagnosticsEngine &Diag, Scope *S, CapturedDecl *CD, - RecordDecl *RD, ImplicitParamDecl *Context, - CapturedRegionKind K) - : CapturingScopeInfo(Diag, ImpCap_CapturedRegion), - TheCapturedDecl(CD), TheRecordDecl(RD), TheScope(S), - ContextParam(Context), CapRegionKind(K) - { - Kind = SK_CapturedRegion; - } - - ~CapturedRegionScopeInfo() override; - - /// \brief A descriptive name for the kind of captured region this is. - StringRef getRegionName() const { - switch (CapRegionKind) { - case CR_Default: - return "default captured statement"; - case CR_OpenMP: - return "OpenMP region"; - } - llvm_unreachable("Invalid captured region kind!"); - } - - static bool classof(const FunctionScopeInfo *FSI) { - return FSI->Kind == SK_CapturedRegion; - } -}; - -class LambdaScopeInfo final : public CapturingScopeInfo { -public: - /// \brief The class that describes the lambda. - CXXRecordDecl *Lambda; - - /// \brief The lambda's compiler-generated \c operator(). - CXXMethodDecl *CallOperator; - - /// \brief Source range covering the lambda introducer [...]. - SourceRange IntroducerRange; - - /// \brief Source location of the '&' or '=' specifying the default capture - /// type, if any. - SourceLocation CaptureDefaultLoc; - - /// \brief The number of captures in the \c Captures list that are - /// explicit captures. - unsigned NumExplicitCaptures; - - /// \brief Whether this is a mutable lambda. - bool Mutable; - - /// \brief Whether the (empty) parameter list is explicit. - bool ExplicitParams; - - /// \brief Whether any of the capture expressions requires cleanups. - bool ExprNeedsCleanups; - - /// \brief Whether the lambda contains an unexpanded parameter pack. - bool ContainsUnexpandedParameterPack; - - /// \brief If this is a generic lambda, use this as the depth of - /// each 'auto' parameter, during initial AST construction. - unsigned AutoTemplateParameterDepth; - - /// \brief Store the list of the auto parameters for a generic lambda. - /// If this is a generic lambda, store the list of the auto - /// parameters converted into TemplateTypeParmDecls into a vector - /// that can be used to construct the generic lambda's template - /// parameter list, during initial AST construction. - SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams; - - /// If this is a generic lambda, and the template parameter - /// list has been created (from the AutoTemplateParams) then - /// store a reference to it (cache it to avoid reconstructing it). - TemplateParameterList *GLTemplateParameterList; - - /// \brief Contains all variable-referring-expressions (i.e. DeclRefExprs - /// or MemberExprs) that refer to local variables in a generic lambda - /// or a lambda in a potentially-evaluated-if-used context. - /// - /// Potentially capturable variables of a nested lambda that might need - /// to be captured by the lambda are housed here. - /// This is specifically useful for generic lambdas or - /// lambdas within a a potentially evaluated-if-used context. - /// If an enclosing variable is named in an expression of a lambda nested - /// within a generic lambda, we don't always know know whether the variable - /// will truly be odr-used (i.e. need to be captured) by that nested lambda, - /// until its instantiation. But we still need to capture it in the - /// enclosing lambda if all intervening lambdas can capture the variable. - - llvm::SmallVector<Expr*, 4> PotentiallyCapturingExprs; - - /// \brief Contains all variable-referring-expressions that refer - /// to local variables that are usable as constant expressions and - /// do not involve an odr-use (they may still need to be captured - /// if the enclosing full-expression is instantiation dependent). - llvm::SmallSet<Expr*, 8> NonODRUsedCapturingExprs; - - SourceLocation PotentialThisCaptureLocation; - - LambdaScopeInfo(DiagnosticsEngine &Diag) - : CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr), - CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false), - ExplicitParams(false), ExprNeedsCleanups(false), - ContainsUnexpandedParameterPack(false), AutoTemplateParameterDepth(0), - GLTemplateParameterList(nullptr) { - Kind = SK_Lambda; - } - - /// \brief Note when all explicit captures have been added. - void finishedExplicitCaptures() { - NumExplicitCaptures = Captures.size(); - } - - static bool classof(const FunctionScopeInfo *FSI) { - return FSI->Kind == SK_Lambda; - } - - /// - /// \brief Add a variable that might potentially be captured by the - /// lambda and therefore the enclosing lambdas. - /// - /// This is also used by enclosing lambda's to speculatively capture - /// variables that nested lambda's - depending on their enclosing - /// specialization - might need to capture. - /// Consider: - /// void f(int, int); <-- don't capture - /// void f(const int&, double); <-- capture - /// void foo() { - /// const int x = 10; - /// auto L = [=](auto a) { // capture 'x' - /// return [=](auto b) { - /// f(x, a); // we may or may not need to capture 'x' - /// }; - /// }; - /// } - void addPotentialCapture(Expr *VarExpr) { - assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr)); - PotentiallyCapturingExprs.push_back(VarExpr); - } - - void addPotentialThisCapture(SourceLocation Loc) { - PotentialThisCaptureLocation = Loc; - } - bool hasPotentialThisCapture() const { - return PotentialThisCaptureLocation.isValid(); - } - - /// \brief Mark a variable's reference in a lambda as non-odr using. - /// - /// For generic lambdas, if a variable is named in a potentially evaluated - /// expression, where the enclosing full expression is dependent then we - /// must capture the variable (given a default capture). - /// This is accomplished by recording all references to variables - /// (DeclRefExprs or MemberExprs) within said nested lambda in its array of - /// PotentialCaptures. All such variables have to be captured by that lambda, - /// except for as described below. - /// If that variable is usable as a constant expression and is named in a - /// manner that does not involve its odr-use (e.g. undergoes - /// lvalue-to-rvalue conversion, or discarded) record that it is so. Upon the - /// act of analyzing the enclosing full expression (ActOnFinishFullExpr) - /// if we can determine that the full expression is not instantiation- - /// dependent, then we can entirely avoid its capture. - /// - /// const int n = 0; - /// [&] (auto x) { - /// (void)+n + x; - /// }; - /// Interestingly, this strategy would involve a capture of n, even though - /// it's obviously not odr-used here, because the full-expression is - /// instantiation-dependent. It could be useful to avoid capturing such - /// variables, even when they are referred to in an instantiation-dependent - /// expression, if we can unambiguously determine that they shall never be - /// odr-used. This would involve removal of the variable-referring-expression - /// from the array of PotentialCaptures during the lvalue-to-rvalue - /// conversions. But per the working draft N3797, (post-chicago 2013) we must - /// capture such variables. - /// Before anyone is tempted to implement a strategy for not-capturing 'n', - /// consider the insightful warning in: - /// /cfe-commits/Week-of-Mon-20131104/092596.html - /// "The problem is that the set of captures for a lambda is part of the ABI - /// (since lambda layout can be made visible through inline functions and the - /// like), and there are no guarantees as to which cases we'll manage to build - /// an lvalue-to-rvalue conversion in, when parsing a template -- some - /// seemingly harmless change elsewhere in Sema could cause us to start or stop - /// building such a node. So we need a rule that anyone can implement and get - /// exactly the same result". - /// - void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) { - assert(isa<DeclRefExpr>(CapturingVarExpr) - || isa<MemberExpr>(CapturingVarExpr)); - NonODRUsedCapturingExprs.insert(CapturingVarExpr); - } - bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) const { - assert(isa<DeclRefExpr>(CapturingVarExpr) - || isa<MemberExpr>(CapturingVarExpr)); - return NonODRUsedCapturingExprs.count(CapturingVarExpr); - } - void removePotentialCapture(Expr *E) { - PotentiallyCapturingExprs.erase( - std::remove(PotentiallyCapturingExprs.begin(), - PotentiallyCapturingExprs.end(), E), - PotentiallyCapturingExprs.end()); - } - void clearPotentialCaptures() { - PotentiallyCapturingExprs.clear(); - PotentialThisCaptureLocation = SourceLocation(); - } - unsigned getNumPotentialVariableCaptures() const { - return PotentiallyCapturingExprs.size(); - } - - bool hasPotentialCaptures() const { - return getNumPotentialVariableCaptures() || - PotentialThisCaptureLocation.isValid(); - } - - // When passed the index, returns the VarDecl and Expr associated - // with the index. - void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const; -}; - -FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy() - : Base(nullptr, false), Property(nullptr) {} - -FunctionScopeInfo::WeakObjectProfileTy -FunctionScopeInfo::WeakObjectProfileTy::getSentinel() { - FunctionScopeInfo::WeakObjectProfileTy Result; - Result.Base.setInt(true); - return Result; -} - -template <typename ExprT> -void FunctionScopeInfo::recordUseOfWeak(const ExprT *E, bool IsRead) { - assert(E); - WeakUseVector &Uses = WeakObjectUses[WeakObjectProfileTy(E)]; - Uses.push_back(WeakUseTy(E, IsRead)); -} - -inline void -CapturingScopeInfo::addThisCapture(bool isNested, SourceLocation Loc, - QualType CaptureType, Expr *Cpy) { - Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType, - Cpy)); - CXXThisCaptureIndex = Captures.size(); -} - -} // end namespace sema -} // end namespace clang - -#endif |