106f32e7eSjoerg //===- ScopeInfo.h - Information about a semantic context -------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file defines FunctionScopeInfo and its subclasses, which contain
1006f32e7eSjoerg // information about a single function, block, lambda, or method body.
1106f32e7eSjoerg //
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg
1406f32e7eSjoerg #ifndef LLVM_CLANG_SEMA_SCOPEINFO_H
1506f32e7eSjoerg #define LLVM_CLANG_SEMA_SCOPEINFO_H
1606f32e7eSjoerg
1706f32e7eSjoerg #include "clang/AST/Expr.h"
1806f32e7eSjoerg #include "clang/AST/ExprCXX.h"
1906f32e7eSjoerg #include "clang/AST/Type.h"
2006f32e7eSjoerg #include "clang/Basic/CapturedStmt.h"
2106f32e7eSjoerg #include "clang/Basic/LLVM.h"
2206f32e7eSjoerg #include "clang/Basic/PartialDiagnostic.h"
2306f32e7eSjoerg #include "clang/Basic/SourceLocation.h"
2406f32e7eSjoerg #include "clang/Sema/CleanupInfo.h"
25*13fbcb42Sjoerg #include "clang/Sema/DeclSpec.h"
2606f32e7eSjoerg #include "llvm/ADT/DenseMap.h"
2706f32e7eSjoerg #include "llvm/ADT/DenseMapInfo.h"
2806f32e7eSjoerg #include "llvm/ADT/MapVector.h"
2906f32e7eSjoerg #include "llvm/ADT/PointerIntPair.h"
3006f32e7eSjoerg #include "llvm/ADT/SmallPtrSet.h"
3106f32e7eSjoerg #include "llvm/ADT/SmallSet.h"
3206f32e7eSjoerg #include "llvm/ADT/SmallVector.h"
3306f32e7eSjoerg #include "llvm/ADT/StringRef.h"
3406f32e7eSjoerg #include "llvm/ADT/StringSwitch.h"
3506f32e7eSjoerg #include "llvm/ADT/TinyPtrVector.h"
3606f32e7eSjoerg #include "llvm/Support/Casting.h"
3706f32e7eSjoerg #include "llvm/Support/ErrorHandling.h"
3806f32e7eSjoerg #include <algorithm>
3906f32e7eSjoerg #include <cassert>
4006f32e7eSjoerg #include <utility>
4106f32e7eSjoerg
4206f32e7eSjoerg namespace clang {
4306f32e7eSjoerg
4406f32e7eSjoerg class BlockDecl;
4506f32e7eSjoerg class CapturedDecl;
4606f32e7eSjoerg class CXXMethodDecl;
4706f32e7eSjoerg class CXXRecordDecl;
4806f32e7eSjoerg class ImplicitParamDecl;
4906f32e7eSjoerg class NamedDecl;
5006f32e7eSjoerg class ObjCIvarRefExpr;
5106f32e7eSjoerg class ObjCMessageExpr;
5206f32e7eSjoerg class ObjCPropertyDecl;
5306f32e7eSjoerg class ObjCPropertyRefExpr;
5406f32e7eSjoerg class ParmVarDecl;
5506f32e7eSjoerg class RecordDecl;
5606f32e7eSjoerg class ReturnStmt;
5706f32e7eSjoerg class Scope;
5806f32e7eSjoerg class Stmt;
5906f32e7eSjoerg class SwitchStmt;
6006f32e7eSjoerg class TemplateParameterList;
6106f32e7eSjoerg class TemplateTypeParmDecl;
6206f32e7eSjoerg class VarDecl;
6306f32e7eSjoerg
6406f32e7eSjoerg namespace sema {
6506f32e7eSjoerg
6606f32e7eSjoerg /// Contains information about the compound statement currently being
6706f32e7eSjoerg /// parsed.
6806f32e7eSjoerg class CompoundScopeInfo {
6906f32e7eSjoerg public:
7006f32e7eSjoerg /// Whether this compound stamement contains `for' or `while' loops
7106f32e7eSjoerg /// with empty bodies.
7206f32e7eSjoerg bool HasEmptyLoopBodies = false;
7306f32e7eSjoerg
7406f32e7eSjoerg /// Whether this compound statement corresponds to a GNU statement
7506f32e7eSjoerg /// expression.
7606f32e7eSjoerg bool IsStmtExpr;
7706f32e7eSjoerg
CompoundScopeInfo(bool IsStmtExpr)7806f32e7eSjoerg CompoundScopeInfo(bool IsStmtExpr) : IsStmtExpr(IsStmtExpr) {}
7906f32e7eSjoerg
setHasEmptyLoopBodies()8006f32e7eSjoerg void setHasEmptyLoopBodies() {
8106f32e7eSjoerg HasEmptyLoopBodies = true;
8206f32e7eSjoerg }
8306f32e7eSjoerg };
8406f32e7eSjoerg
8506f32e7eSjoerg class PossiblyUnreachableDiag {
8606f32e7eSjoerg public:
8706f32e7eSjoerg PartialDiagnostic PD;
8806f32e7eSjoerg SourceLocation Loc;
8906f32e7eSjoerg llvm::TinyPtrVector<const Stmt*> Stmts;
9006f32e7eSjoerg
PossiblyUnreachableDiag(const PartialDiagnostic & PD,SourceLocation Loc,ArrayRef<const Stmt * > Stmts)9106f32e7eSjoerg PossiblyUnreachableDiag(const PartialDiagnostic &PD, SourceLocation Loc,
9206f32e7eSjoerg ArrayRef<const Stmt *> Stmts)
9306f32e7eSjoerg : PD(PD), Loc(Loc), Stmts(Stmts) {}
9406f32e7eSjoerg };
9506f32e7eSjoerg
9606f32e7eSjoerg /// Retains information about a function, method, or block that is
9706f32e7eSjoerg /// currently being parsed.
9806f32e7eSjoerg class FunctionScopeInfo {
9906f32e7eSjoerg protected:
10006f32e7eSjoerg enum ScopeKind {
10106f32e7eSjoerg SK_Function,
10206f32e7eSjoerg SK_Block,
10306f32e7eSjoerg SK_Lambda,
10406f32e7eSjoerg SK_CapturedRegion
10506f32e7eSjoerg };
10606f32e7eSjoerg
10706f32e7eSjoerg public:
10806f32e7eSjoerg /// What kind of scope we are describing.
10906f32e7eSjoerg ScopeKind Kind : 3;
11006f32e7eSjoerg
11106f32e7eSjoerg /// Whether this function contains a VLA, \@try, try, C++
11206f32e7eSjoerg /// initializer, or anything else that can't be jumped past.
11306f32e7eSjoerg bool HasBranchProtectedScope : 1;
11406f32e7eSjoerg
11506f32e7eSjoerg /// Whether this function contains any switches or direct gotos.
11606f32e7eSjoerg bool HasBranchIntoScope : 1;
11706f32e7eSjoerg
11806f32e7eSjoerg /// Whether this function contains any indirect gotos.
11906f32e7eSjoerg bool HasIndirectGoto : 1;
12006f32e7eSjoerg
121*13fbcb42Sjoerg /// Whether this function contains any statement marked with
122*13fbcb42Sjoerg /// \c [[clang::musttail]].
123*13fbcb42Sjoerg bool HasMustTail : 1;
124*13fbcb42Sjoerg
12506f32e7eSjoerg /// Whether a statement was dropped because it was invalid.
12606f32e7eSjoerg bool HasDroppedStmt : 1;
12706f32e7eSjoerg
12806f32e7eSjoerg /// True if current scope is for OpenMP declare reduction combiner.
12906f32e7eSjoerg bool HasOMPDeclareReductionCombiner : 1;
13006f32e7eSjoerg
13106f32e7eSjoerg /// Whether there is a fallthrough statement in this function.
13206f32e7eSjoerg bool HasFallthroughStmt : 1;
13306f32e7eSjoerg
134*13fbcb42Sjoerg /// Whether this function uses constrained floating point intrinsics
135*13fbcb42Sjoerg bool UsesFPIntrin : 1;
136*13fbcb42Sjoerg
13706f32e7eSjoerg /// Whether we make reference to a declaration that could be
13806f32e7eSjoerg /// unavailable.
13906f32e7eSjoerg bool HasPotentialAvailabilityViolations : 1;
14006f32e7eSjoerg
14106f32e7eSjoerg /// A flag that is set when parsing a method that must call super's
14206f32e7eSjoerg /// implementation, such as \c -dealloc, \c -finalize, or any method marked
14306f32e7eSjoerg /// with \c __attribute__((objc_requires_super)).
14406f32e7eSjoerg bool ObjCShouldCallSuper : 1;
14506f32e7eSjoerg
14606f32e7eSjoerg /// True when this is a method marked as a designated initializer.
14706f32e7eSjoerg bool ObjCIsDesignatedInit : 1;
14806f32e7eSjoerg
14906f32e7eSjoerg /// This starts true for a method marked as designated initializer and will
15006f32e7eSjoerg /// be set to false if there is an invocation to a designated initializer of
15106f32e7eSjoerg /// the super class.
15206f32e7eSjoerg bool ObjCWarnForNoDesignatedInitChain : 1;
15306f32e7eSjoerg
15406f32e7eSjoerg /// True when this is an initializer method not marked as a designated
15506f32e7eSjoerg /// initializer within a class that has at least one initializer marked as a
15606f32e7eSjoerg /// designated initializer.
15706f32e7eSjoerg bool ObjCIsSecondaryInit : 1;
15806f32e7eSjoerg
15906f32e7eSjoerg /// This starts true for a secondary initializer method and will be set to
16006f32e7eSjoerg /// false if there is an invocation of an initializer on 'self'.
16106f32e7eSjoerg bool ObjCWarnForNoInitDelegation : 1;
16206f32e7eSjoerg
16306f32e7eSjoerg /// True only when this function has not already built, or attempted
16406f32e7eSjoerg /// to build, the initial and final coroutine suspend points
16506f32e7eSjoerg bool NeedsCoroutineSuspends : 1;
16606f32e7eSjoerg
16706f32e7eSjoerg /// An enumeration represeting the kind of the first coroutine statement
16806f32e7eSjoerg /// in the function. One of co_return, co_await, or co_yield.
16906f32e7eSjoerg unsigned char FirstCoroutineStmtKind : 2;
17006f32e7eSjoerg
17106f32e7eSjoerg /// First coroutine statement in the current function.
17206f32e7eSjoerg /// (ex co_return, co_await, co_yield)
17306f32e7eSjoerg SourceLocation FirstCoroutineStmtLoc;
17406f32e7eSjoerg
17506f32e7eSjoerg /// First 'return' statement in the current function.
17606f32e7eSjoerg SourceLocation FirstReturnLoc;
17706f32e7eSjoerg
17806f32e7eSjoerg /// First C++ 'try' statement in the current function.
17906f32e7eSjoerg SourceLocation FirstCXXTryLoc;
18006f32e7eSjoerg
18106f32e7eSjoerg /// First SEH '__try' statement in the current function.
18206f32e7eSjoerg SourceLocation FirstSEHTryLoc;
18306f32e7eSjoerg
184*13fbcb42Sjoerg private:
18506f32e7eSjoerg /// Used to determine if errors occurred in this function or block.
18606f32e7eSjoerg DiagnosticErrorTrap ErrorTrap;
18706f32e7eSjoerg
188*13fbcb42Sjoerg public:
18906f32e7eSjoerg /// A SwitchStmt, along with a flag indicating if its list of case statements
19006f32e7eSjoerg /// is incomplete (because we dropped an invalid one while parsing).
19106f32e7eSjoerg using SwitchInfo = llvm::PointerIntPair<SwitchStmt*, 1, bool>;
19206f32e7eSjoerg
19306f32e7eSjoerg /// SwitchStack - This is the current set of active switch statements in the
19406f32e7eSjoerg /// block.
19506f32e7eSjoerg SmallVector<SwitchInfo, 8> SwitchStack;
19606f32e7eSjoerg
19706f32e7eSjoerg /// The list of return statements that occur within the function or
19806f32e7eSjoerg /// block, if there is any chance of applying the named return value
19906f32e7eSjoerg /// optimization, or if we need to infer a return type.
20006f32e7eSjoerg SmallVector<ReturnStmt*, 4> Returns;
20106f32e7eSjoerg
20206f32e7eSjoerg /// The promise object for this coroutine, if any.
20306f32e7eSjoerg VarDecl *CoroutinePromise = nullptr;
20406f32e7eSjoerg
20506f32e7eSjoerg /// A mapping between the coroutine function parameters that were moved
20606f32e7eSjoerg /// to the coroutine frame, and their move statements.
20706f32e7eSjoerg llvm::SmallMapVector<ParmVarDecl *, Stmt *, 4> CoroutineParameterMoves;
20806f32e7eSjoerg
20906f32e7eSjoerg /// The initial and final coroutine suspend points.
21006f32e7eSjoerg std::pair<Stmt *, Stmt *> CoroutineSuspends;
21106f32e7eSjoerg
21206f32e7eSjoerg /// The stack of currently active compound stamement scopes in the
21306f32e7eSjoerg /// function.
21406f32e7eSjoerg SmallVector<CompoundScopeInfo, 4> CompoundScopes;
21506f32e7eSjoerg
21606f32e7eSjoerg /// The set of blocks that are introduced in this function.
21706f32e7eSjoerg llvm::SmallPtrSet<const BlockDecl *, 1> Blocks;
21806f32e7eSjoerg
21906f32e7eSjoerg /// The set of __block variables that are introduced in this function.
22006f32e7eSjoerg llvm::TinyPtrVector<VarDecl *> ByrefBlockVars;
22106f32e7eSjoerg
22206f32e7eSjoerg /// A list of PartialDiagnostics created but delayed within the
22306f32e7eSjoerg /// current function scope. These diagnostics are vetted for reachability
22406f32e7eSjoerg /// prior to being emitted.
22506f32e7eSjoerg SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags;
22606f32e7eSjoerg
22706f32e7eSjoerg /// A list of parameters which have the nonnull attribute and are
22806f32e7eSjoerg /// modified in the function.
22906f32e7eSjoerg llvm::SmallPtrSet<const ParmVarDecl *, 8> ModifiedNonNullParams;
23006f32e7eSjoerg
23106f32e7eSjoerg public:
23206f32e7eSjoerg /// Represents a simple identification of a weak object.
23306f32e7eSjoerg ///
23406f32e7eSjoerg /// Part of the implementation of -Wrepeated-use-of-weak.
23506f32e7eSjoerg ///
23606f32e7eSjoerg /// This is used to determine if two weak accesses refer to the same object.
23706f32e7eSjoerg /// Here are some examples of how various accesses are "profiled":
23806f32e7eSjoerg ///
23906f32e7eSjoerg /// Access Expression | "Base" Decl | "Property" Decl
24006f32e7eSjoerg /// :---------------: | :-----------------: | :------------------------------:
24106f32e7eSjoerg /// self.property | self (VarDecl) | property (ObjCPropertyDecl)
24206f32e7eSjoerg /// self.implicitProp | self (VarDecl) | -implicitProp (ObjCMethodDecl)
24306f32e7eSjoerg /// self->ivar.prop | ivar (ObjCIvarDecl) | prop (ObjCPropertyDecl)
24406f32e7eSjoerg /// cxxObj.obj.prop | obj (FieldDecl) | prop (ObjCPropertyDecl)
24506f32e7eSjoerg /// [self foo].prop | 0 (unknown) | prop (ObjCPropertyDecl)
24606f32e7eSjoerg /// self.prop1.prop2 | prop1 (ObjCPropertyDecl) | prop2 (ObjCPropertyDecl)
24706f32e7eSjoerg /// MyClass.prop | MyClass (ObjCInterfaceDecl) | -prop (ObjCMethodDecl)
24806f32e7eSjoerg /// MyClass.foo.prop | +foo (ObjCMethodDecl) | -prop (ObjCPropertyDecl)
24906f32e7eSjoerg /// weakVar | 0 (known) | weakVar (VarDecl)
25006f32e7eSjoerg /// self->weakIvar | self (VarDecl) | weakIvar (ObjCIvarDecl)
25106f32e7eSjoerg ///
25206f32e7eSjoerg /// Objects are identified with only two Decls to make it reasonably fast to
25306f32e7eSjoerg /// compare them.
25406f32e7eSjoerg class WeakObjectProfileTy {
25506f32e7eSjoerg /// The base object decl, as described in the class documentation.
25606f32e7eSjoerg ///
25706f32e7eSjoerg /// The extra flag is "true" if the Base and Property are enough to uniquely
25806f32e7eSjoerg /// identify the object in memory.
25906f32e7eSjoerg ///
26006f32e7eSjoerg /// \sa isExactProfile()
26106f32e7eSjoerg using BaseInfoTy = llvm::PointerIntPair<const NamedDecl *, 1, bool>;
26206f32e7eSjoerg BaseInfoTy Base;
26306f32e7eSjoerg
26406f32e7eSjoerg /// The "property" decl, as described in the class documentation.
26506f32e7eSjoerg ///
26606f32e7eSjoerg /// Note that this may not actually be an ObjCPropertyDecl, e.g. in the
26706f32e7eSjoerg /// case of "implicit" properties (regular methods accessed via dot syntax).
26806f32e7eSjoerg const NamedDecl *Property = nullptr;
26906f32e7eSjoerg
27006f32e7eSjoerg /// Used to find the proper base profile for a given base expression.
27106f32e7eSjoerg static BaseInfoTy getBaseInfo(const Expr *BaseE);
27206f32e7eSjoerg
27306f32e7eSjoerg inline WeakObjectProfileTy();
27406f32e7eSjoerg static inline WeakObjectProfileTy getSentinel();
27506f32e7eSjoerg
27606f32e7eSjoerg public:
27706f32e7eSjoerg WeakObjectProfileTy(const ObjCPropertyRefExpr *RE);
27806f32e7eSjoerg WeakObjectProfileTy(const Expr *Base, const ObjCPropertyDecl *Property);
27906f32e7eSjoerg WeakObjectProfileTy(const DeclRefExpr *RE);
28006f32e7eSjoerg WeakObjectProfileTy(const ObjCIvarRefExpr *RE);
28106f32e7eSjoerg
getBase()28206f32e7eSjoerg const NamedDecl *getBase() const { return Base.getPointer(); }
getProperty()28306f32e7eSjoerg const NamedDecl *getProperty() const { return Property; }
28406f32e7eSjoerg
28506f32e7eSjoerg /// Returns true if the object base specifies a known object in memory,
28606f32e7eSjoerg /// rather than, say, an instance variable or property of another object.
28706f32e7eSjoerg ///
28806f32e7eSjoerg /// Note that this ignores the effects of aliasing; that is, \c foo.bar is
28906f32e7eSjoerg /// considered an exact profile if \c foo is a local variable, even if
29006f32e7eSjoerg /// another variable \c foo2 refers to the same object as \c foo.
29106f32e7eSjoerg ///
29206f32e7eSjoerg /// For increased precision, accesses with base variables that are
29306f32e7eSjoerg /// properties or ivars of 'self' (e.g. self.prop1.prop2) are considered to
29406f32e7eSjoerg /// be exact, though this is not true for arbitrary variables
29506f32e7eSjoerg /// (foo.prop1.prop2).
isExactProfile()29606f32e7eSjoerg bool isExactProfile() const {
29706f32e7eSjoerg return Base.getInt();
29806f32e7eSjoerg }
29906f32e7eSjoerg
30006f32e7eSjoerg bool operator==(const WeakObjectProfileTy &Other) const {
30106f32e7eSjoerg return Base == Other.Base && Property == Other.Property;
30206f32e7eSjoerg }
30306f32e7eSjoerg
30406f32e7eSjoerg // For use in DenseMap.
30506f32e7eSjoerg // We can't specialize the usual llvm::DenseMapInfo at the end of the file
30606f32e7eSjoerg // because by that point the DenseMap in FunctionScopeInfo has already been
30706f32e7eSjoerg // instantiated.
30806f32e7eSjoerg class DenseMapInfo {
30906f32e7eSjoerg public:
getEmptyKey()31006f32e7eSjoerg static inline WeakObjectProfileTy getEmptyKey() {
31106f32e7eSjoerg return WeakObjectProfileTy();
31206f32e7eSjoerg }
31306f32e7eSjoerg
getTombstoneKey()31406f32e7eSjoerg static inline WeakObjectProfileTy getTombstoneKey() {
31506f32e7eSjoerg return WeakObjectProfileTy::getSentinel();
31606f32e7eSjoerg }
31706f32e7eSjoerg
getHashValue(const WeakObjectProfileTy & Val)31806f32e7eSjoerg static unsigned getHashValue(const WeakObjectProfileTy &Val) {
31906f32e7eSjoerg using Pair = std::pair<BaseInfoTy, const NamedDecl *>;
32006f32e7eSjoerg
32106f32e7eSjoerg return llvm::DenseMapInfo<Pair>::getHashValue(Pair(Val.Base,
32206f32e7eSjoerg Val.Property));
32306f32e7eSjoerg }
32406f32e7eSjoerg
isEqual(const WeakObjectProfileTy & LHS,const WeakObjectProfileTy & RHS)32506f32e7eSjoerg static bool isEqual(const WeakObjectProfileTy &LHS,
32606f32e7eSjoerg const WeakObjectProfileTy &RHS) {
32706f32e7eSjoerg return LHS == RHS;
32806f32e7eSjoerg }
32906f32e7eSjoerg };
33006f32e7eSjoerg };
33106f32e7eSjoerg
33206f32e7eSjoerg /// Represents a single use of a weak object.
33306f32e7eSjoerg ///
33406f32e7eSjoerg /// Stores both the expression and whether the access is potentially unsafe
33506f32e7eSjoerg /// (i.e. it could potentially be warned about).
33606f32e7eSjoerg ///
33706f32e7eSjoerg /// Part of the implementation of -Wrepeated-use-of-weak.
33806f32e7eSjoerg class WeakUseTy {
33906f32e7eSjoerg llvm::PointerIntPair<const Expr *, 1, bool> Rep;
34006f32e7eSjoerg
34106f32e7eSjoerg public:
WeakUseTy(const Expr * Use,bool IsRead)34206f32e7eSjoerg WeakUseTy(const Expr *Use, bool IsRead) : Rep(Use, IsRead) {}
34306f32e7eSjoerg
getUseExpr()34406f32e7eSjoerg const Expr *getUseExpr() const { return Rep.getPointer(); }
isUnsafe()34506f32e7eSjoerg bool isUnsafe() const { return Rep.getInt(); }
markSafe()34606f32e7eSjoerg void markSafe() { Rep.setInt(false); }
34706f32e7eSjoerg
34806f32e7eSjoerg bool operator==(const WeakUseTy &Other) const {
34906f32e7eSjoerg return Rep == Other.Rep;
35006f32e7eSjoerg }
35106f32e7eSjoerg };
35206f32e7eSjoerg
35306f32e7eSjoerg /// Used to collect uses of a particular weak object in a function body.
35406f32e7eSjoerg ///
35506f32e7eSjoerg /// Part of the implementation of -Wrepeated-use-of-weak.
35606f32e7eSjoerg using WeakUseVector = SmallVector<WeakUseTy, 4>;
35706f32e7eSjoerg
35806f32e7eSjoerg /// Used to collect all uses of weak objects in a function body.
35906f32e7eSjoerg ///
36006f32e7eSjoerg /// Part of the implementation of -Wrepeated-use-of-weak.
36106f32e7eSjoerg using WeakObjectUseMap =
36206f32e7eSjoerg llvm::SmallDenseMap<WeakObjectProfileTy, WeakUseVector, 8,
36306f32e7eSjoerg WeakObjectProfileTy::DenseMapInfo>;
36406f32e7eSjoerg
36506f32e7eSjoerg private:
36606f32e7eSjoerg /// Used to collect all uses of weak objects in this function body.
36706f32e7eSjoerg ///
36806f32e7eSjoerg /// Part of the implementation of -Wrepeated-use-of-weak.
36906f32e7eSjoerg WeakObjectUseMap WeakObjectUses;
37006f32e7eSjoerg
37106f32e7eSjoerg protected:
37206f32e7eSjoerg FunctionScopeInfo(const FunctionScopeInfo&) = default;
37306f32e7eSjoerg
37406f32e7eSjoerg public:
FunctionScopeInfo(DiagnosticsEngine & Diag)37506f32e7eSjoerg FunctionScopeInfo(DiagnosticsEngine &Diag)
37606f32e7eSjoerg : Kind(SK_Function), HasBranchProtectedScope(false),
377*13fbcb42Sjoerg HasBranchIntoScope(false), HasIndirectGoto(false), HasMustTail(false),
37806f32e7eSjoerg HasDroppedStmt(false), HasOMPDeclareReductionCombiner(false),
379*13fbcb42Sjoerg HasFallthroughStmt(false), UsesFPIntrin(false),
380*13fbcb42Sjoerg HasPotentialAvailabilityViolations(false), ObjCShouldCallSuper(false),
381*13fbcb42Sjoerg ObjCIsDesignatedInit(false), ObjCWarnForNoDesignatedInitChain(false),
382*13fbcb42Sjoerg ObjCIsSecondaryInit(false), ObjCWarnForNoInitDelegation(false),
383*13fbcb42Sjoerg NeedsCoroutineSuspends(true), ErrorTrap(Diag) {}
38406f32e7eSjoerg
38506f32e7eSjoerg virtual ~FunctionScopeInfo();
38606f32e7eSjoerg
387*13fbcb42Sjoerg /// Determine whether an unrecoverable error has occurred within this
388*13fbcb42Sjoerg /// function. Note that this may return false even if the function body is
389*13fbcb42Sjoerg /// invalid, because the errors may be suppressed if they're caused by prior
390*13fbcb42Sjoerg /// invalid declarations.
391*13fbcb42Sjoerg ///
392*13fbcb42Sjoerg /// FIXME: Migrate the caller of this to use containsErrors() instead once
393*13fbcb42Sjoerg /// it's ready.
hasUnrecoverableErrorOccurred()394*13fbcb42Sjoerg bool hasUnrecoverableErrorOccurred() const {
395*13fbcb42Sjoerg return ErrorTrap.hasUnrecoverableErrorOccurred();
396*13fbcb42Sjoerg }
397*13fbcb42Sjoerg
39806f32e7eSjoerg /// Record that a weak object was accessed.
39906f32e7eSjoerg ///
40006f32e7eSjoerg /// Part of the implementation of -Wrepeated-use-of-weak.
40106f32e7eSjoerg template <typename ExprT>
40206f32e7eSjoerg inline void recordUseOfWeak(const ExprT *E, bool IsRead = true);
40306f32e7eSjoerg
40406f32e7eSjoerg void recordUseOfWeak(const ObjCMessageExpr *Msg,
40506f32e7eSjoerg const ObjCPropertyDecl *Prop);
40606f32e7eSjoerg
40706f32e7eSjoerg /// Record that a given expression is a "safe" access of a weak object (e.g.
40806f32e7eSjoerg /// assigning it to a strong variable.)
40906f32e7eSjoerg ///
41006f32e7eSjoerg /// Part of the implementation of -Wrepeated-use-of-weak.
41106f32e7eSjoerg void markSafeWeakUse(const Expr *E);
41206f32e7eSjoerg
getWeakObjectUses()41306f32e7eSjoerg const WeakObjectUseMap &getWeakObjectUses() const {
41406f32e7eSjoerg return WeakObjectUses;
41506f32e7eSjoerg }
41606f32e7eSjoerg
setHasBranchIntoScope()41706f32e7eSjoerg void setHasBranchIntoScope() {
41806f32e7eSjoerg HasBranchIntoScope = true;
41906f32e7eSjoerg }
42006f32e7eSjoerg
setHasBranchProtectedScope()42106f32e7eSjoerg void setHasBranchProtectedScope() {
42206f32e7eSjoerg HasBranchProtectedScope = true;
42306f32e7eSjoerg }
42406f32e7eSjoerg
setHasIndirectGoto()42506f32e7eSjoerg void setHasIndirectGoto() {
42606f32e7eSjoerg HasIndirectGoto = true;
42706f32e7eSjoerg }
42806f32e7eSjoerg
setHasMustTail()429*13fbcb42Sjoerg void setHasMustTail() { HasMustTail = true; }
430*13fbcb42Sjoerg
setHasDroppedStmt()43106f32e7eSjoerg void setHasDroppedStmt() {
43206f32e7eSjoerg HasDroppedStmt = true;
43306f32e7eSjoerg }
43406f32e7eSjoerg
setHasOMPDeclareReductionCombiner()43506f32e7eSjoerg void setHasOMPDeclareReductionCombiner() {
43606f32e7eSjoerg HasOMPDeclareReductionCombiner = true;
43706f32e7eSjoerg }
43806f32e7eSjoerg
setHasFallthroughStmt()43906f32e7eSjoerg void setHasFallthroughStmt() {
44006f32e7eSjoerg HasFallthroughStmt = true;
44106f32e7eSjoerg }
44206f32e7eSjoerg
setUsesFPIntrin()443*13fbcb42Sjoerg void setUsesFPIntrin() {
444*13fbcb42Sjoerg UsesFPIntrin = true;
445*13fbcb42Sjoerg }
446*13fbcb42Sjoerg
setHasCXXTry(SourceLocation TryLoc)44706f32e7eSjoerg void setHasCXXTry(SourceLocation TryLoc) {
44806f32e7eSjoerg setHasBranchProtectedScope();
44906f32e7eSjoerg FirstCXXTryLoc = TryLoc;
45006f32e7eSjoerg }
45106f32e7eSjoerg
setHasSEHTry(SourceLocation TryLoc)45206f32e7eSjoerg void setHasSEHTry(SourceLocation TryLoc) {
45306f32e7eSjoerg setHasBranchProtectedScope();
45406f32e7eSjoerg FirstSEHTryLoc = TryLoc;
45506f32e7eSjoerg }
45606f32e7eSjoerg
NeedsScopeChecking()45706f32e7eSjoerg bool NeedsScopeChecking() const {
458*13fbcb42Sjoerg return !HasDroppedStmt && (HasIndirectGoto || HasMustTail ||
45906f32e7eSjoerg (HasBranchProtectedScope && HasBranchIntoScope));
46006f32e7eSjoerg }
46106f32e7eSjoerg
46206f32e7eSjoerg // Add a block introduced in this function.
addBlock(const BlockDecl * BD)46306f32e7eSjoerg void addBlock(const BlockDecl *BD) {
46406f32e7eSjoerg Blocks.insert(BD);
46506f32e7eSjoerg }
46606f32e7eSjoerg
46706f32e7eSjoerg // Add a __block variable introduced in this function.
addByrefBlockVar(VarDecl * VD)46806f32e7eSjoerg void addByrefBlockVar(VarDecl *VD) {
46906f32e7eSjoerg ByrefBlockVars.push_back(VD);
47006f32e7eSjoerg }
47106f32e7eSjoerg
isCoroutine()47206f32e7eSjoerg bool isCoroutine() const { return !FirstCoroutineStmtLoc.isInvalid(); }
47306f32e7eSjoerg
setFirstCoroutineStmt(SourceLocation Loc,StringRef Keyword)47406f32e7eSjoerg void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) {
47506f32e7eSjoerg assert(FirstCoroutineStmtLoc.isInvalid() &&
47606f32e7eSjoerg "first coroutine statement location already set");
47706f32e7eSjoerg FirstCoroutineStmtLoc = Loc;
47806f32e7eSjoerg FirstCoroutineStmtKind = llvm::StringSwitch<unsigned char>(Keyword)
47906f32e7eSjoerg .Case("co_return", 0)
48006f32e7eSjoerg .Case("co_await", 1)
48106f32e7eSjoerg .Case("co_yield", 2);
48206f32e7eSjoerg }
48306f32e7eSjoerg
getFirstCoroutineStmtKeyword()48406f32e7eSjoerg StringRef getFirstCoroutineStmtKeyword() const {
48506f32e7eSjoerg assert(FirstCoroutineStmtLoc.isValid()
48606f32e7eSjoerg && "no coroutine statement available");
48706f32e7eSjoerg switch (FirstCoroutineStmtKind) {
48806f32e7eSjoerg case 0: return "co_return";
48906f32e7eSjoerg case 1: return "co_await";
49006f32e7eSjoerg case 2: return "co_yield";
49106f32e7eSjoerg default:
49206f32e7eSjoerg llvm_unreachable("FirstCoroutineStmtKind has an invalid value");
49306f32e7eSjoerg };
49406f32e7eSjoerg }
49506f32e7eSjoerg
49606f32e7eSjoerg void setNeedsCoroutineSuspends(bool value = true) {
49706f32e7eSjoerg assert((!value || CoroutineSuspends.first == nullptr) &&
49806f32e7eSjoerg "we already have valid suspend points");
49906f32e7eSjoerg NeedsCoroutineSuspends = value;
50006f32e7eSjoerg }
50106f32e7eSjoerg
hasInvalidCoroutineSuspends()50206f32e7eSjoerg bool hasInvalidCoroutineSuspends() const {
50306f32e7eSjoerg return !NeedsCoroutineSuspends && CoroutineSuspends.first == nullptr;
50406f32e7eSjoerg }
50506f32e7eSjoerg
setCoroutineSuspends(Stmt * Initial,Stmt * Final)50606f32e7eSjoerg void setCoroutineSuspends(Stmt *Initial, Stmt *Final) {
50706f32e7eSjoerg assert(Initial && Final && "suspend points cannot be null");
50806f32e7eSjoerg assert(CoroutineSuspends.first == nullptr && "suspend points already set");
50906f32e7eSjoerg NeedsCoroutineSuspends = false;
51006f32e7eSjoerg CoroutineSuspends.first = Initial;
51106f32e7eSjoerg CoroutineSuspends.second = Final;
51206f32e7eSjoerg }
51306f32e7eSjoerg
51406f32e7eSjoerg /// Clear out the information in this function scope, making it
51506f32e7eSjoerg /// suitable for reuse.
51606f32e7eSjoerg void Clear();
51706f32e7eSjoerg
isPlainFunction()51806f32e7eSjoerg bool isPlainFunction() const { return Kind == SK_Function; }
51906f32e7eSjoerg };
52006f32e7eSjoerg
52106f32e7eSjoerg class Capture {
52206f32e7eSjoerg // There are three categories of capture: capturing 'this', capturing
52306f32e7eSjoerg // local variables, and C++1y initialized captures (which can have an
52406f32e7eSjoerg // arbitrary initializer, and don't really capture in the traditional
52506f32e7eSjoerg // sense at all).
52606f32e7eSjoerg //
52706f32e7eSjoerg // There are three ways to capture a local variable:
52806f32e7eSjoerg // - capture by copy in the C++11 sense,
52906f32e7eSjoerg // - capture by reference in the C++11 sense, and
53006f32e7eSjoerg // - __block capture.
53106f32e7eSjoerg // Lambdas explicitly specify capture by copy or capture by reference.
53206f32e7eSjoerg // For blocks, __block capture applies to variables with that annotation,
53306f32e7eSjoerg // variables of reference type are captured by reference, and other
53406f32e7eSjoerg // variables are captured by copy.
53506f32e7eSjoerg enum CaptureKind {
53606f32e7eSjoerg Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_VLA
53706f32e7eSjoerg };
53806f32e7eSjoerg
53906f32e7eSjoerg union {
54006f32e7eSjoerg /// If Kind == Cap_VLA, the captured type.
54106f32e7eSjoerg const VariableArrayType *CapturedVLA;
54206f32e7eSjoerg
54306f32e7eSjoerg /// Otherwise, the captured variable (if any).
54406f32e7eSjoerg VarDecl *CapturedVar;
54506f32e7eSjoerg };
54606f32e7eSjoerg
54706f32e7eSjoerg /// The source location at which the first capture occurred.
54806f32e7eSjoerg SourceLocation Loc;
54906f32e7eSjoerg
55006f32e7eSjoerg /// The location of the ellipsis that expands a parameter pack.
55106f32e7eSjoerg SourceLocation EllipsisLoc;
55206f32e7eSjoerg
55306f32e7eSjoerg /// The type as it was captured, which is the type of the non-static data
55406f32e7eSjoerg /// member that would hold the capture.
55506f32e7eSjoerg QualType CaptureType;
55606f32e7eSjoerg
55706f32e7eSjoerg /// The CaptureKind of this capture.
55806f32e7eSjoerg unsigned Kind : 2;
55906f32e7eSjoerg
56006f32e7eSjoerg /// Whether this is a nested capture (a capture of an enclosing capturing
56106f32e7eSjoerg /// scope's capture).
56206f32e7eSjoerg unsigned Nested : 1;
56306f32e7eSjoerg
56406f32e7eSjoerg /// Whether this is a capture of '*this'.
56506f32e7eSjoerg unsigned CapturesThis : 1;
56606f32e7eSjoerg
56706f32e7eSjoerg /// Whether an explicit capture has been odr-used in the body of the
56806f32e7eSjoerg /// lambda.
56906f32e7eSjoerg unsigned ODRUsed : 1;
57006f32e7eSjoerg
57106f32e7eSjoerg /// Whether an explicit capture has been non-odr-used in the body of
57206f32e7eSjoerg /// the lambda.
57306f32e7eSjoerg unsigned NonODRUsed : 1;
57406f32e7eSjoerg
57506f32e7eSjoerg /// Whether the capture is invalid (a capture was required but the entity is
57606f32e7eSjoerg /// non-capturable).
57706f32e7eSjoerg unsigned Invalid : 1;
57806f32e7eSjoerg
57906f32e7eSjoerg public:
Capture(VarDecl * Var,bool Block,bool ByRef,bool IsNested,SourceLocation Loc,SourceLocation EllipsisLoc,QualType CaptureType,bool Invalid)58006f32e7eSjoerg Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
58106f32e7eSjoerg SourceLocation Loc, SourceLocation EllipsisLoc, QualType CaptureType,
58206f32e7eSjoerg bool Invalid)
58306f32e7eSjoerg : CapturedVar(Var), Loc(Loc), EllipsisLoc(EllipsisLoc),
58406f32e7eSjoerg CaptureType(CaptureType),
58506f32e7eSjoerg Kind(Block ? Cap_Block : ByRef ? Cap_ByRef : Cap_ByCopy),
58606f32e7eSjoerg Nested(IsNested), CapturesThis(false), ODRUsed(false),
58706f32e7eSjoerg NonODRUsed(false), Invalid(Invalid) {}
58806f32e7eSjoerg
58906f32e7eSjoerg enum IsThisCapture { ThisCapture };
Capture(IsThisCapture,bool IsNested,SourceLocation Loc,QualType CaptureType,const bool ByCopy,bool Invalid)59006f32e7eSjoerg Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
59106f32e7eSjoerg QualType CaptureType, const bool ByCopy, bool Invalid)
59206f32e7eSjoerg : Loc(Loc), CaptureType(CaptureType),
59306f32e7eSjoerg Kind(ByCopy ? Cap_ByCopy : Cap_ByRef), Nested(IsNested),
59406f32e7eSjoerg CapturesThis(true), ODRUsed(false), NonODRUsed(false),
59506f32e7eSjoerg Invalid(Invalid) {}
59606f32e7eSjoerg
59706f32e7eSjoerg enum IsVLACapture { VLACapture };
Capture(IsVLACapture,const VariableArrayType * VLA,bool IsNested,SourceLocation Loc,QualType CaptureType)59806f32e7eSjoerg Capture(IsVLACapture, const VariableArrayType *VLA, bool IsNested,
59906f32e7eSjoerg SourceLocation Loc, QualType CaptureType)
60006f32e7eSjoerg : CapturedVLA(VLA), Loc(Loc), CaptureType(CaptureType), Kind(Cap_VLA),
60106f32e7eSjoerg Nested(IsNested), CapturesThis(false), ODRUsed(false),
60206f32e7eSjoerg NonODRUsed(false), Invalid(false) {}
60306f32e7eSjoerg
isThisCapture()60406f32e7eSjoerg bool isThisCapture() const { return CapturesThis; }
isVariableCapture()60506f32e7eSjoerg bool isVariableCapture() const {
60606f32e7eSjoerg return !isThisCapture() && !isVLATypeCapture();
60706f32e7eSjoerg }
60806f32e7eSjoerg
isCopyCapture()60906f32e7eSjoerg bool isCopyCapture() const { return Kind == Cap_ByCopy; }
isReferenceCapture()61006f32e7eSjoerg bool isReferenceCapture() const { return Kind == Cap_ByRef; }
isBlockCapture()61106f32e7eSjoerg bool isBlockCapture() const { return Kind == Cap_Block; }
isVLATypeCapture()61206f32e7eSjoerg bool isVLATypeCapture() const { return Kind == Cap_VLA; }
61306f32e7eSjoerg
isNested()61406f32e7eSjoerg bool isNested() const { return Nested; }
61506f32e7eSjoerg
isInvalid()61606f32e7eSjoerg bool isInvalid() const { return Invalid; }
61706f32e7eSjoerg
61806f32e7eSjoerg /// Determine whether this capture is an init-capture.
61906f32e7eSjoerg bool isInitCapture() const;
62006f32e7eSjoerg
isODRUsed()62106f32e7eSjoerg bool isODRUsed() const { return ODRUsed; }
isNonODRUsed()62206f32e7eSjoerg bool isNonODRUsed() const { return NonODRUsed; }
markUsed(bool IsODRUse)62306f32e7eSjoerg void markUsed(bool IsODRUse) {
62406f32e7eSjoerg if (IsODRUse)
62506f32e7eSjoerg ODRUsed = true;
62606f32e7eSjoerg else
62706f32e7eSjoerg NonODRUsed = true;
62806f32e7eSjoerg }
62906f32e7eSjoerg
getVariable()63006f32e7eSjoerg VarDecl *getVariable() const {
63106f32e7eSjoerg assert(isVariableCapture());
63206f32e7eSjoerg return CapturedVar;
63306f32e7eSjoerg }
63406f32e7eSjoerg
getCapturedVLAType()63506f32e7eSjoerg const VariableArrayType *getCapturedVLAType() const {
63606f32e7eSjoerg assert(isVLATypeCapture());
63706f32e7eSjoerg return CapturedVLA;
63806f32e7eSjoerg }
63906f32e7eSjoerg
64006f32e7eSjoerg /// Retrieve the location at which this variable was captured.
getLocation()64106f32e7eSjoerg SourceLocation getLocation() const { return Loc; }
64206f32e7eSjoerg
64306f32e7eSjoerg /// Retrieve the source location of the ellipsis, whose presence
64406f32e7eSjoerg /// indicates that the capture is a pack expansion.
getEllipsisLoc()64506f32e7eSjoerg SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
64606f32e7eSjoerg
64706f32e7eSjoerg /// Retrieve the capture type for this capture, which is effectively
64806f32e7eSjoerg /// the type of the non-static data member in the lambda/block structure
64906f32e7eSjoerg /// that would store this capture.
getCaptureType()65006f32e7eSjoerg QualType getCaptureType() const { return CaptureType; }
65106f32e7eSjoerg };
65206f32e7eSjoerg
65306f32e7eSjoerg class CapturingScopeInfo : public FunctionScopeInfo {
65406f32e7eSjoerg protected:
65506f32e7eSjoerg CapturingScopeInfo(const CapturingScopeInfo&) = default;
65606f32e7eSjoerg
65706f32e7eSjoerg public:
65806f32e7eSjoerg enum ImplicitCaptureStyle {
65906f32e7eSjoerg ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block,
66006f32e7eSjoerg ImpCap_CapturedRegion
66106f32e7eSjoerg };
66206f32e7eSjoerg
66306f32e7eSjoerg ImplicitCaptureStyle ImpCaptureStyle;
66406f32e7eSjoerg
CapturingScopeInfo(DiagnosticsEngine & Diag,ImplicitCaptureStyle Style)66506f32e7eSjoerg CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style)
66606f32e7eSjoerg : FunctionScopeInfo(Diag), ImpCaptureStyle(Style) {}
66706f32e7eSjoerg
66806f32e7eSjoerg /// CaptureMap - A map of captured variables to (index+1) into Captures.
66906f32e7eSjoerg llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
67006f32e7eSjoerg
67106f32e7eSjoerg /// CXXThisCaptureIndex - The (index+1) of the capture of 'this';
67206f32e7eSjoerg /// zero if 'this' is not captured.
67306f32e7eSjoerg unsigned CXXThisCaptureIndex = 0;
67406f32e7eSjoerg
67506f32e7eSjoerg /// Captures - The captures.
67606f32e7eSjoerg SmallVector<Capture, 4> Captures;
67706f32e7eSjoerg
67806f32e7eSjoerg /// - Whether the target type of return statements in this context
67906f32e7eSjoerg /// is deduced (e.g. a lambda or block with omitted return type).
68006f32e7eSjoerg bool HasImplicitReturnType = false;
68106f32e7eSjoerg
68206f32e7eSjoerg /// ReturnType - The target type of return statements in this context,
68306f32e7eSjoerg /// or null if unknown.
68406f32e7eSjoerg QualType ReturnType;
68506f32e7eSjoerg
addCapture(VarDecl * Var,bool isBlock,bool isByref,bool isNested,SourceLocation Loc,SourceLocation EllipsisLoc,QualType CaptureType,bool Invalid)68606f32e7eSjoerg void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
68706f32e7eSjoerg SourceLocation Loc, SourceLocation EllipsisLoc,
68806f32e7eSjoerg QualType CaptureType, bool Invalid) {
68906f32e7eSjoerg Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc,
69006f32e7eSjoerg EllipsisLoc, CaptureType, Invalid));
69106f32e7eSjoerg CaptureMap[Var] = Captures.size();
69206f32e7eSjoerg }
69306f32e7eSjoerg
addVLATypeCapture(SourceLocation Loc,const VariableArrayType * VLAType,QualType CaptureType)69406f32e7eSjoerg void addVLATypeCapture(SourceLocation Loc, const VariableArrayType *VLAType,
69506f32e7eSjoerg QualType CaptureType) {
69606f32e7eSjoerg Captures.push_back(Capture(Capture::VLACapture, VLAType,
69706f32e7eSjoerg /*FIXME: IsNested*/ false, Loc, CaptureType));
69806f32e7eSjoerg }
69906f32e7eSjoerg
70006f32e7eSjoerg void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
70106f32e7eSjoerg bool ByCopy);
70206f32e7eSjoerg
70306f32e7eSjoerg /// Determine whether the C++ 'this' is captured.
isCXXThisCaptured()70406f32e7eSjoerg bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; }
70506f32e7eSjoerg
70606f32e7eSjoerg /// Retrieve the capture of C++ 'this', if it has been captured.
getCXXThisCapture()70706f32e7eSjoerg Capture &getCXXThisCapture() {
70806f32e7eSjoerg assert(isCXXThisCaptured() && "this has not been captured");
70906f32e7eSjoerg return Captures[CXXThisCaptureIndex - 1];
71006f32e7eSjoerg }
71106f32e7eSjoerg
71206f32e7eSjoerg /// Determine whether the given variable has been captured.
isCaptured(VarDecl * Var)71306f32e7eSjoerg bool isCaptured(VarDecl *Var) const {
71406f32e7eSjoerg return CaptureMap.count(Var);
71506f32e7eSjoerg }
71606f32e7eSjoerg
71706f32e7eSjoerg /// Determine whether the given variable-array type has been captured.
71806f32e7eSjoerg bool isVLATypeCaptured(const VariableArrayType *VAT) const;
71906f32e7eSjoerg
72006f32e7eSjoerg /// Retrieve the capture of the given variable, if it has been
72106f32e7eSjoerg /// captured already.
getCapture(VarDecl * Var)72206f32e7eSjoerg Capture &getCapture(VarDecl *Var) {
72306f32e7eSjoerg assert(isCaptured(Var) && "Variable has not been captured");
72406f32e7eSjoerg return Captures[CaptureMap[Var] - 1];
72506f32e7eSjoerg }
72606f32e7eSjoerg
getCapture(VarDecl * Var)72706f32e7eSjoerg const Capture &getCapture(VarDecl *Var) const {
72806f32e7eSjoerg llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known
72906f32e7eSjoerg = CaptureMap.find(Var);
73006f32e7eSjoerg assert(Known != CaptureMap.end() && "Variable has not been captured");
73106f32e7eSjoerg return Captures[Known->second - 1];
73206f32e7eSjoerg }
73306f32e7eSjoerg
classof(const FunctionScopeInfo * FSI)73406f32e7eSjoerg static bool classof(const FunctionScopeInfo *FSI) {
73506f32e7eSjoerg return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda
73606f32e7eSjoerg || FSI->Kind == SK_CapturedRegion;
73706f32e7eSjoerg }
73806f32e7eSjoerg };
73906f32e7eSjoerg
74006f32e7eSjoerg /// Retains information about a block that is currently being parsed.
74106f32e7eSjoerg class BlockScopeInfo final : public CapturingScopeInfo {
74206f32e7eSjoerg public:
74306f32e7eSjoerg BlockDecl *TheDecl;
74406f32e7eSjoerg
74506f32e7eSjoerg /// TheScope - This is the scope for the block itself, which contains
74606f32e7eSjoerg /// arguments etc.
74706f32e7eSjoerg Scope *TheScope;
74806f32e7eSjoerg
74906f32e7eSjoerg /// BlockType - The function type of the block, if one was given.
75006f32e7eSjoerg /// Its return type may be BuiltinType::Dependent.
75106f32e7eSjoerg QualType FunctionType;
75206f32e7eSjoerg
BlockScopeInfo(DiagnosticsEngine & Diag,Scope * BlockScope,BlockDecl * Block)75306f32e7eSjoerg BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block)
75406f32e7eSjoerg : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block),
75506f32e7eSjoerg TheScope(BlockScope) {
75606f32e7eSjoerg Kind = SK_Block;
75706f32e7eSjoerg }
75806f32e7eSjoerg
75906f32e7eSjoerg ~BlockScopeInfo() override;
76006f32e7eSjoerg
classof(const FunctionScopeInfo * FSI)76106f32e7eSjoerg static bool classof(const FunctionScopeInfo *FSI) {
76206f32e7eSjoerg return FSI->Kind == SK_Block;
76306f32e7eSjoerg }
76406f32e7eSjoerg };
76506f32e7eSjoerg
76606f32e7eSjoerg /// Retains information about a captured region.
76706f32e7eSjoerg class CapturedRegionScopeInfo final : public CapturingScopeInfo {
76806f32e7eSjoerg public:
76906f32e7eSjoerg /// The CapturedDecl for this statement.
77006f32e7eSjoerg CapturedDecl *TheCapturedDecl;
77106f32e7eSjoerg
77206f32e7eSjoerg /// The captured record type.
77306f32e7eSjoerg RecordDecl *TheRecordDecl;
77406f32e7eSjoerg
77506f32e7eSjoerg /// This is the enclosing scope of the captured region.
77606f32e7eSjoerg Scope *TheScope;
77706f32e7eSjoerg
77806f32e7eSjoerg /// The implicit parameter for the captured variables.
77906f32e7eSjoerg ImplicitParamDecl *ContextParam;
78006f32e7eSjoerg
78106f32e7eSjoerg /// The kind of captured region.
78206f32e7eSjoerg unsigned short CapRegionKind;
78306f32e7eSjoerg
78406f32e7eSjoerg unsigned short OpenMPLevel;
78506f32e7eSjoerg unsigned short OpenMPCaptureLevel;
78606f32e7eSjoerg
CapturedRegionScopeInfo(DiagnosticsEngine & Diag,Scope * S,CapturedDecl * CD,RecordDecl * RD,ImplicitParamDecl * Context,CapturedRegionKind K,unsigned OpenMPLevel,unsigned OpenMPCaptureLevel)78706f32e7eSjoerg CapturedRegionScopeInfo(DiagnosticsEngine &Diag, Scope *S, CapturedDecl *CD,
78806f32e7eSjoerg RecordDecl *RD, ImplicitParamDecl *Context,
78906f32e7eSjoerg CapturedRegionKind K, unsigned OpenMPLevel,
79006f32e7eSjoerg unsigned OpenMPCaptureLevel)
79106f32e7eSjoerg : CapturingScopeInfo(Diag, ImpCap_CapturedRegion),
79206f32e7eSjoerg TheCapturedDecl(CD), TheRecordDecl(RD), TheScope(S),
79306f32e7eSjoerg ContextParam(Context), CapRegionKind(K), OpenMPLevel(OpenMPLevel),
79406f32e7eSjoerg OpenMPCaptureLevel(OpenMPCaptureLevel) {
79506f32e7eSjoerg Kind = SK_CapturedRegion;
79606f32e7eSjoerg }
79706f32e7eSjoerg
79806f32e7eSjoerg ~CapturedRegionScopeInfo() override;
79906f32e7eSjoerg
80006f32e7eSjoerg /// A descriptive name for the kind of captured region this is.
getRegionName()80106f32e7eSjoerg StringRef getRegionName() const {
80206f32e7eSjoerg switch (CapRegionKind) {
80306f32e7eSjoerg case CR_Default:
80406f32e7eSjoerg return "default captured statement";
80506f32e7eSjoerg case CR_ObjCAtFinally:
80606f32e7eSjoerg return "Objective-C @finally statement";
80706f32e7eSjoerg case CR_OpenMP:
80806f32e7eSjoerg return "OpenMP region";
80906f32e7eSjoerg }
81006f32e7eSjoerg llvm_unreachable("Invalid captured region kind!");
81106f32e7eSjoerg }
81206f32e7eSjoerg
classof(const FunctionScopeInfo * FSI)81306f32e7eSjoerg static bool classof(const FunctionScopeInfo *FSI) {
81406f32e7eSjoerg return FSI->Kind == SK_CapturedRegion;
81506f32e7eSjoerg }
81606f32e7eSjoerg };
81706f32e7eSjoerg
818*13fbcb42Sjoerg class LambdaScopeInfo final :
819*13fbcb42Sjoerg public CapturingScopeInfo, public InventedTemplateParameterInfo {
82006f32e7eSjoerg public:
82106f32e7eSjoerg /// The class that describes the lambda.
82206f32e7eSjoerg CXXRecordDecl *Lambda = nullptr;
82306f32e7eSjoerg
82406f32e7eSjoerg /// The lambda's compiler-generated \c operator().
82506f32e7eSjoerg CXXMethodDecl *CallOperator = nullptr;
82606f32e7eSjoerg
82706f32e7eSjoerg /// Source range covering the lambda introducer [...].
82806f32e7eSjoerg SourceRange IntroducerRange;
82906f32e7eSjoerg
83006f32e7eSjoerg /// Source location of the '&' or '=' specifying the default capture
83106f32e7eSjoerg /// type, if any.
83206f32e7eSjoerg SourceLocation CaptureDefaultLoc;
83306f32e7eSjoerg
83406f32e7eSjoerg /// The number of captures in the \c Captures list that are
83506f32e7eSjoerg /// explicit captures.
83606f32e7eSjoerg unsigned NumExplicitCaptures = 0;
83706f32e7eSjoerg
83806f32e7eSjoerg /// Whether this is a mutable lambda.
83906f32e7eSjoerg bool Mutable = false;
84006f32e7eSjoerg
84106f32e7eSjoerg /// Whether the (empty) parameter list is explicit.
84206f32e7eSjoerg bool ExplicitParams = false;
84306f32e7eSjoerg
84406f32e7eSjoerg /// Whether any of the capture expressions requires cleanups.
84506f32e7eSjoerg CleanupInfo Cleanup;
84606f32e7eSjoerg
84706f32e7eSjoerg /// Whether the lambda contains an unexpanded parameter pack.
84806f32e7eSjoerg bool ContainsUnexpandedParameterPack = false;
84906f32e7eSjoerg
85006f32e7eSjoerg /// Packs introduced by this lambda, if any.
85106f32e7eSjoerg SmallVector<NamedDecl*, 4> LocalPacks;
85206f32e7eSjoerg
85306f32e7eSjoerg /// Source range covering the explicit template parameter list (if it exists).
85406f32e7eSjoerg SourceRange ExplicitTemplateParamsRange;
85506f32e7eSjoerg
856*13fbcb42Sjoerg /// The requires-clause immediately following the explicit template parameter
857*13fbcb42Sjoerg /// list, if any. (Note that there may be another requires-clause included as
858*13fbcb42Sjoerg /// part of the lambda-declarator.)
859*13fbcb42Sjoerg ExprResult RequiresClause;
86006f32e7eSjoerg
86106f32e7eSjoerg /// If this is a generic lambda, and the template parameter
86206f32e7eSjoerg /// list has been created (from the TemplateParams) then store
86306f32e7eSjoerg /// a reference to it (cache it to avoid reconstructing it).
86406f32e7eSjoerg TemplateParameterList *GLTemplateParameterList = nullptr;
86506f32e7eSjoerg
86606f32e7eSjoerg /// Contains all variable-referring-expressions (i.e. DeclRefExprs
86706f32e7eSjoerg /// or MemberExprs) that refer to local variables in a generic lambda
86806f32e7eSjoerg /// or a lambda in a potentially-evaluated-if-used context.
86906f32e7eSjoerg ///
87006f32e7eSjoerg /// Potentially capturable variables of a nested lambda that might need
87106f32e7eSjoerg /// to be captured by the lambda are housed here.
87206f32e7eSjoerg /// This is specifically useful for generic lambdas or
87306f32e7eSjoerg /// lambdas within a potentially evaluated-if-used context.
87406f32e7eSjoerg /// If an enclosing variable is named in an expression of a lambda nested
87506f32e7eSjoerg /// within a generic lambda, we don't always know know whether the variable
87606f32e7eSjoerg /// will truly be odr-used (i.e. need to be captured) by that nested lambda,
87706f32e7eSjoerg /// until its instantiation. But we still need to capture it in the
87806f32e7eSjoerg /// enclosing lambda if all intervening lambdas can capture the variable.
87906f32e7eSjoerg llvm::SmallVector<Expr*, 4> PotentiallyCapturingExprs;
88006f32e7eSjoerg
88106f32e7eSjoerg /// Contains all variable-referring-expressions that refer
88206f32e7eSjoerg /// to local variables that are usable as constant expressions and
88306f32e7eSjoerg /// do not involve an odr-use (they may still need to be captured
88406f32e7eSjoerg /// if the enclosing full-expression is instantiation dependent).
88506f32e7eSjoerg llvm::SmallSet<Expr *, 8> NonODRUsedCapturingExprs;
88606f32e7eSjoerg
88706f32e7eSjoerg /// A map of explicit capture indices to their introducer source ranges.
88806f32e7eSjoerg llvm::DenseMap<unsigned, SourceRange> ExplicitCaptureRanges;
88906f32e7eSjoerg
89006f32e7eSjoerg /// Contains all of the variables defined in this lambda that shadow variables
89106f32e7eSjoerg /// that were defined in parent contexts. Used to avoid warnings when the
89206f32e7eSjoerg /// shadowed variables are uncaptured by this lambda.
89306f32e7eSjoerg struct ShadowedOuterDecl {
89406f32e7eSjoerg const VarDecl *VD;
89506f32e7eSjoerg const VarDecl *ShadowedDecl;
89606f32e7eSjoerg };
89706f32e7eSjoerg llvm::SmallVector<ShadowedOuterDecl, 4> ShadowingDecls;
89806f32e7eSjoerg
89906f32e7eSjoerg SourceLocation PotentialThisCaptureLocation;
90006f32e7eSjoerg
LambdaScopeInfo(DiagnosticsEngine & Diag)90106f32e7eSjoerg LambdaScopeInfo(DiagnosticsEngine &Diag)
90206f32e7eSjoerg : CapturingScopeInfo(Diag, ImpCap_None) {
90306f32e7eSjoerg Kind = SK_Lambda;
90406f32e7eSjoerg }
90506f32e7eSjoerg
90606f32e7eSjoerg /// Note when all explicit captures have been added.
finishedExplicitCaptures()90706f32e7eSjoerg void finishedExplicitCaptures() {
90806f32e7eSjoerg NumExplicitCaptures = Captures.size();
90906f32e7eSjoerg }
91006f32e7eSjoerg
classof(const FunctionScopeInfo * FSI)91106f32e7eSjoerg static bool classof(const FunctionScopeInfo *FSI) {
91206f32e7eSjoerg return FSI->Kind == SK_Lambda;
91306f32e7eSjoerg }
91406f32e7eSjoerg
91506f32e7eSjoerg /// Is this scope known to be for a generic lambda? (This will be false until
91606f32e7eSjoerg /// we parse a template parameter list or the first 'auto'-typed parameter).
isGenericLambda()91706f32e7eSjoerg bool isGenericLambda() const {
91806f32e7eSjoerg return !TemplateParams.empty() || GLTemplateParameterList;
91906f32e7eSjoerg }
92006f32e7eSjoerg
92106f32e7eSjoerg /// Add a variable that might potentially be captured by the
92206f32e7eSjoerg /// lambda and therefore the enclosing lambdas.
92306f32e7eSjoerg ///
92406f32e7eSjoerg /// This is also used by enclosing lambda's to speculatively capture
92506f32e7eSjoerg /// variables that nested lambda's - depending on their enclosing
92606f32e7eSjoerg /// specialization - might need to capture.
92706f32e7eSjoerg /// Consider:
92806f32e7eSjoerg /// void f(int, int); <-- don't capture
92906f32e7eSjoerg /// void f(const int&, double); <-- capture
93006f32e7eSjoerg /// void foo() {
93106f32e7eSjoerg /// const int x = 10;
93206f32e7eSjoerg /// auto L = [=](auto a) { // capture 'x'
93306f32e7eSjoerg /// return [=](auto b) {
93406f32e7eSjoerg /// f(x, a); // we may or may not need to capture 'x'
93506f32e7eSjoerg /// };
93606f32e7eSjoerg /// };
93706f32e7eSjoerg /// }
addPotentialCapture(Expr * VarExpr)93806f32e7eSjoerg void addPotentialCapture(Expr *VarExpr) {
93906f32e7eSjoerg assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr) ||
94006f32e7eSjoerg isa<FunctionParmPackExpr>(VarExpr));
94106f32e7eSjoerg PotentiallyCapturingExprs.push_back(VarExpr);
94206f32e7eSjoerg }
94306f32e7eSjoerg
addPotentialThisCapture(SourceLocation Loc)94406f32e7eSjoerg void addPotentialThisCapture(SourceLocation Loc) {
94506f32e7eSjoerg PotentialThisCaptureLocation = Loc;
94606f32e7eSjoerg }
94706f32e7eSjoerg
hasPotentialThisCapture()94806f32e7eSjoerg bool hasPotentialThisCapture() const {
94906f32e7eSjoerg return PotentialThisCaptureLocation.isValid();
95006f32e7eSjoerg }
95106f32e7eSjoerg
95206f32e7eSjoerg /// Mark a variable's reference in a lambda as non-odr using.
95306f32e7eSjoerg ///
95406f32e7eSjoerg /// For generic lambdas, if a variable is named in a potentially evaluated
95506f32e7eSjoerg /// expression, where the enclosing full expression is dependent then we
95606f32e7eSjoerg /// must capture the variable (given a default capture).
95706f32e7eSjoerg /// This is accomplished by recording all references to variables
95806f32e7eSjoerg /// (DeclRefExprs or MemberExprs) within said nested lambda in its array of
95906f32e7eSjoerg /// PotentialCaptures. All such variables have to be captured by that lambda,
96006f32e7eSjoerg /// except for as described below.
96106f32e7eSjoerg /// If that variable is usable as a constant expression and is named in a
96206f32e7eSjoerg /// manner that does not involve its odr-use (e.g. undergoes
96306f32e7eSjoerg /// lvalue-to-rvalue conversion, or discarded) record that it is so. Upon the
96406f32e7eSjoerg /// act of analyzing the enclosing full expression (ActOnFinishFullExpr)
96506f32e7eSjoerg /// if we can determine that the full expression is not instantiation-
96606f32e7eSjoerg /// dependent, then we can entirely avoid its capture.
96706f32e7eSjoerg ///
96806f32e7eSjoerg /// const int n = 0;
96906f32e7eSjoerg /// [&] (auto x) {
97006f32e7eSjoerg /// (void)+n + x;
97106f32e7eSjoerg /// };
97206f32e7eSjoerg /// Interestingly, this strategy would involve a capture of n, even though
97306f32e7eSjoerg /// it's obviously not odr-used here, because the full-expression is
97406f32e7eSjoerg /// instantiation-dependent. It could be useful to avoid capturing such
97506f32e7eSjoerg /// variables, even when they are referred to in an instantiation-dependent
97606f32e7eSjoerg /// expression, if we can unambiguously determine that they shall never be
97706f32e7eSjoerg /// odr-used. This would involve removal of the variable-referring-expression
97806f32e7eSjoerg /// from the array of PotentialCaptures during the lvalue-to-rvalue
97906f32e7eSjoerg /// conversions. But per the working draft N3797, (post-chicago 2013) we must
98006f32e7eSjoerg /// capture such variables.
98106f32e7eSjoerg /// Before anyone is tempted to implement a strategy for not-capturing 'n',
98206f32e7eSjoerg /// consider the insightful warning in:
98306f32e7eSjoerg /// /cfe-commits/Week-of-Mon-20131104/092596.html
98406f32e7eSjoerg /// "The problem is that the set of captures for a lambda is part of the ABI
98506f32e7eSjoerg /// (since lambda layout can be made visible through inline functions and the
98606f32e7eSjoerg /// like), and there are no guarantees as to which cases we'll manage to build
98706f32e7eSjoerg /// an lvalue-to-rvalue conversion in, when parsing a template -- some
98806f32e7eSjoerg /// seemingly harmless change elsewhere in Sema could cause us to start or stop
98906f32e7eSjoerg /// building such a node. So we need a rule that anyone can implement and get
99006f32e7eSjoerg /// exactly the same result".
markVariableExprAsNonODRUsed(Expr * CapturingVarExpr)99106f32e7eSjoerg void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) {
99206f32e7eSjoerg assert(isa<DeclRefExpr>(CapturingVarExpr) ||
99306f32e7eSjoerg isa<MemberExpr>(CapturingVarExpr) ||
99406f32e7eSjoerg isa<FunctionParmPackExpr>(CapturingVarExpr));
99506f32e7eSjoerg NonODRUsedCapturingExprs.insert(CapturingVarExpr);
99606f32e7eSjoerg }
isVariableExprMarkedAsNonODRUsed(Expr * CapturingVarExpr)99706f32e7eSjoerg bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) const {
99806f32e7eSjoerg assert(isa<DeclRefExpr>(CapturingVarExpr) ||
99906f32e7eSjoerg isa<MemberExpr>(CapturingVarExpr) ||
100006f32e7eSjoerg isa<FunctionParmPackExpr>(CapturingVarExpr));
100106f32e7eSjoerg return NonODRUsedCapturingExprs.count(CapturingVarExpr);
100206f32e7eSjoerg }
removePotentialCapture(Expr * E)100306f32e7eSjoerg void removePotentialCapture(Expr *E) {
100406f32e7eSjoerg PotentiallyCapturingExprs.erase(
100506f32e7eSjoerg std::remove(PotentiallyCapturingExprs.begin(),
100606f32e7eSjoerg PotentiallyCapturingExprs.end(), E),
100706f32e7eSjoerg PotentiallyCapturingExprs.end());
100806f32e7eSjoerg }
clearPotentialCaptures()100906f32e7eSjoerg void clearPotentialCaptures() {
101006f32e7eSjoerg PotentiallyCapturingExprs.clear();
101106f32e7eSjoerg PotentialThisCaptureLocation = SourceLocation();
101206f32e7eSjoerg }
getNumPotentialVariableCaptures()101306f32e7eSjoerg unsigned getNumPotentialVariableCaptures() const {
101406f32e7eSjoerg return PotentiallyCapturingExprs.size();
101506f32e7eSjoerg }
101606f32e7eSjoerg
hasPotentialCaptures()101706f32e7eSjoerg bool hasPotentialCaptures() const {
101806f32e7eSjoerg return getNumPotentialVariableCaptures() ||
101906f32e7eSjoerg PotentialThisCaptureLocation.isValid();
102006f32e7eSjoerg }
102106f32e7eSjoerg
102206f32e7eSjoerg void visitPotentialCaptures(
102306f32e7eSjoerg llvm::function_ref<void(VarDecl *, Expr *)> Callback) const;
102406f32e7eSjoerg };
102506f32e7eSjoerg
WeakObjectProfileTy()102606f32e7eSjoerg FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy()
102706f32e7eSjoerg : Base(nullptr, false) {}
102806f32e7eSjoerg
102906f32e7eSjoerg FunctionScopeInfo::WeakObjectProfileTy
getSentinel()103006f32e7eSjoerg FunctionScopeInfo::WeakObjectProfileTy::getSentinel() {
103106f32e7eSjoerg FunctionScopeInfo::WeakObjectProfileTy Result;
103206f32e7eSjoerg Result.Base.setInt(true);
103306f32e7eSjoerg return Result;
103406f32e7eSjoerg }
103506f32e7eSjoerg
103606f32e7eSjoerg template <typename ExprT>
recordUseOfWeak(const ExprT * E,bool IsRead)103706f32e7eSjoerg void FunctionScopeInfo::recordUseOfWeak(const ExprT *E, bool IsRead) {
103806f32e7eSjoerg assert(E);
103906f32e7eSjoerg WeakUseVector &Uses = WeakObjectUses[WeakObjectProfileTy(E)];
104006f32e7eSjoerg Uses.push_back(WeakUseTy(E, IsRead));
104106f32e7eSjoerg }
104206f32e7eSjoerg
addThisCapture(bool isNested,SourceLocation Loc,QualType CaptureType,bool ByCopy)104306f32e7eSjoerg inline void CapturingScopeInfo::addThisCapture(bool isNested,
104406f32e7eSjoerg SourceLocation Loc,
104506f32e7eSjoerg QualType CaptureType,
104606f32e7eSjoerg bool ByCopy) {
104706f32e7eSjoerg Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType,
104806f32e7eSjoerg ByCopy, /*Invalid*/ false));
104906f32e7eSjoerg CXXThisCaptureIndex = Captures.size();
105006f32e7eSjoerg }
105106f32e7eSjoerg
105206f32e7eSjoerg } // namespace sema
105306f32e7eSjoerg
105406f32e7eSjoerg } // namespace clang
105506f32e7eSjoerg
105606f32e7eSjoerg #endif // LLVM_CLANG_SEMA_SCOPEINFO_H
1057