123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- Scope.h - Scope interface --------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file defines the Scope interface.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CLANG_SEMA_SCOPE_H
- #define LLVM_CLANG_SEMA_SCOPE_H
- #include "clang/AST/Decl.h"
- #include "clang/Basic/Diagnostic.h"
- #include "llvm/ADT/PointerIntPair.h"
- #include "llvm/ADT/SmallPtrSet.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/iterator_range.h"
- #include <cassert>
- #include <optional>
- namespace llvm {
- class raw_ostream;
- } // namespace llvm
- namespace clang {
- class Decl;
- class DeclContext;
- class UsingDirectiveDecl;
- class VarDecl;
- /// Scope - A scope is a transient data structure that is used while parsing the
- /// program. It assists with resolving identifiers to the appropriate
- /// declaration.
- class Scope {
- public:
- /// ScopeFlags - These are bitfields that are or'd together when creating a
- /// scope, which defines the sorts of things the scope contains.
- enum ScopeFlags {
- /// This indicates that the scope corresponds to a function, which
- /// means that labels are set here.
- FnScope = 0x01,
- /// This is a while, do, switch, for, etc that can have break
- /// statements embedded into it.
- BreakScope = 0x02,
- /// This is a while, do, for, which can have continue statements
- /// embedded into it.
- ContinueScope = 0x04,
- /// This is a scope that can contain a declaration. Some scopes
- /// just contain loop constructs but don't contain decls.
- DeclScope = 0x08,
- /// The controlling scope in a if/switch/while/for statement.
- ControlScope = 0x10,
- /// The scope of a struct/union/class definition.
- ClassScope = 0x20,
- /// This is a scope that corresponds to a block/closure object.
- /// Blocks serve as top-level scopes for some objects like labels, they
- /// also prevent things like break and continue. BlockScopes always have
- /// the FnScope and DeclScope flags set as well.
- BlockScope = 0x40,
- /// This is a scope that corresponds to the
- /// template parameters of a C++ template. Template parameter
- /// scope starts at the 'template' keyword and ends when the
- /// template declaration ends.
- TemplateParamScope = 0x80,
- /// This is a scope that corresponds to the
- /// parameters within a function prototype.
- FunctionPrototypeScope = 0x100,
- /// This is a scope that corresponds to the parameters within
- /// a function prototype for a function declaration (as opposed to any
- /// other kind of function declarator). Always has FunctionPrototypeScope
- /// set as well.
- FunctionDeclarationScope = 0x200,
- /// This is a scope that corresponds to the Objective-C
- /// \@catch statement.
- AtCatchScope = 0x400,
- /// This scope corresponds to an Objective-C method body.
- /// It always has FnScope and DeclScope set as well.
- ObjCMethodScope = 0x800,
- /// This is a scope that corresponds to a switch statement.
- SwitchScope = 0x1000,
- /// This is the scope of a C++ try statement.
- TryScope = 0x2000,
- /// This is the scope for a function-level C++ try or catch scope.
- FnTryCatchScope = 0x4000,
- /// This is the scope of OpenMP executable directive.
- OpenMPDirectiveScope = 0x8000,
- /// This is the scope of some OpenMP loop directive.
- OpenMPLoopDirectiveScope = 0x10000,
- /// This is the scope of some OpenMP simd directive.
- /// For example, it is used for 'omp simd', 'omp for simd'.
- /// This flag is propagated to children scopes.
- OpenMPSimdDirectiveScope = 0x20000,
- /// This scope corresponds to an enum.
- EnumScope = 0x40000,
- /// This scope corresponds to an SEH try.
- SEHTryScope = 0x80000,
- /// This scope corresponds to an SEH except.
- SEHExceptScope = 0x100000,
- /// We are currently in the filter expression of an SEH except block.
- SEHFilterScope = 0x200000,
- /// This is a compound statement scope.
- CompoundStmtScope = 0x400000,
- /// We are between inheritance colon and the real class/struct definition
- /// scope.
- ClassInheritanceScope = 0x800000,
- /// This is the scope of a C++ catch statement.
- CatchScope = 0x1000000,
- /// This is a scope in which a condition variable is currently being
- /// parsed. If such a scope is a ContinueScope, it's invalid to jump to the
- /// continue block from here.
- ConditionVarScope = 0x2000000,
- /// This is a scope of some OpenMP directive with
- /// order clause which specifies concurrent
- OpenMPOrderClauseScope = 0x4000000,
- };
- private:
- /// The parent scope for this scope. This is null for the translation-unit
- /// scope.
- Scope *AnyParent;
- /// Flags - This contains a set of ScopeFlags, which indicates how the scope
- /// interrelates with other control flow statements.
- unsigned Flags;
- /// Depth - This is the depth of this scope. The translation-unit scope has
- /// depth 0.
- unsigned short Depth;
- /// Declarations with static linkage are mangled with the number of
- /// scopes seen as a component.
- unsigned short MSLastManglingNumber;
- unsigned short MSCurManglingNumber;
- /// PrototypeDepth - This is the number of function prototype scopes
- /// enclosing this scope, including this scope.
- unsigned short PrototypeDepth;
- /// PrototypeIndex - This is the number of parameters currently
- /// declared in this scope.
- unsigned short PrototypeIndex;
- /// FnParent - If this scope has a parent scope that is a function body, this
- /// pointer is non-null and points to it. This is used for label processing.
- Scope *FnParent;
- Scope *MSLastManglingParent;
- /// BreakParent/ContinueParent - This is a direct link to the innermost
- /// BreakScope/ContinueScope which contains the contents of this scope
- /// for control flow purposes (and might be this scope itself), or null
- /// if there is no such scope.
- Scope *BreakParent, *ContinueParent;
- /// BlockParent - This is a direct link to the immediately containing
- /// BlockScope if this scope is not one, or null if there is none.
- Scope *BlockParent;
- /// TemplateParamParent - This is a direct link to the
- /// immediately containing template parameter scope. In the
- /// case of nested templates, template parameter scopes can have
- /// other template parameter scopes as parents.
- Scope *TemplateParamParent;
- /// DeclsInScope - This keeps track of all declarations in this scope. When
- /// the declaration is added to the scope, it is set as the current
- /// declaration for the identifier in the IdentifierTable. When the scope is
- /// popped, these declarations are removed from the IdentifierTable's notion
- /// of current declaration. It is up to the current Action implementation to
- /// implement these semantics.
- using DeclSetTy = llvm::SmallPtrSet<Decl *, 32>;
- DeclSetTy DeclsInScope;
- /// The DeclContext with which this scope is associated. For
- /// example, the entity of a class scope is the class itself, the
- /// entity of a function scope is a function, etc.
- DeclContext *Entity;
- using UsingDirectivesTy = SmallVector<UsingDirectiveDecl *, 2>;
- UsingDirectivesTy UsingDirectives;
- /// Used to determine if errors occurred in this scope.
- DiagnosticErrorTrap ErrorTrap;
- /// A single NRVO candidate variable in this scope.
- /// There are three possible values:
- /// 1) pointer to VarDecl that denotes NRVO candidate itself.
- /// 2) nullptr value means that NRVO is not allowed in this scope
- /// (e.g. return a function parameter).
- /// 3) std::nullopt value means that there is no NRVO candidate in this scope
- /// (i.e. there are no return statements in this scope).
- std::optional<VarDecl *> NRVO;
- /// Represents return slots for NRVO candidates in the current scope.
- /// If a variable is present in this set, it means that a return slot is
- /// available for this variable in the current scope.
- llvm::SmallPtrSet<VarDecl *, 8> ReturnSlots;
- void setFlags(Scope *Parent, unsigned F);
- public:
- Scope(Scope *Parent, unsigned ScopeFlags, DiagnosticsEngine &Diag)
- : ErrorTrap(Diag) {
- Init(Parent, ScopeFlags);
- }
- /// getFlags - Return the flags for this scope.
- unsigned getFlags() const { return Flags; }
- void setFlags(unsigned F) { setFlags(getParent(), F); }
- /// isBlockScope - Return true if this scope correspond to a closure.
- bool isBlockScope() const { return Flags & BlockScope; }
- /// getParent - Return the scope that this is nested in.
- const Scope *getParent() const { return AnyParent; }
- Scope *getParent() { return AnyParent; }
- /// getFnParent - Return the closest scope that is a function body.
- const Scope *getFnParent() const { return FnParent; }
- Scope *getFnParent() { return FnParent; }
- const Scope *getMSLastManglingParent() const {
- return MSLastManglingParent;
- }
- Scope *getMSLastManglingParent() { return MSLastManglingParent; }
- /// getContinueParent - Return the closest scope that a continue statement
- /// would be affected by.
- Scope *getContinueParent() {
- return ContinueParent;
- }
- const Scope *getContinueParent() const {
- return const_cast<Scope*>(this)->getContinueParent();
- }
- // Set whether we're in the scope of a condition variable, where 'continue'
- // is disallowed despite being a continue scope.
- void setIsConditionVarScope(bool InConditionVarScope) {
- Flags = (Flags & ~ConditionVarScope) |
- (InConditionVarScope ? ConditionVarScope : 0);
- }
- bool isConditionVarScope() const {
- return Flags & ConditionVarScope;
- }
- /// getBreakParent - Return the closest scope that a break statement
- /// would be affected by.
- Scope *getBreakParent() {
- return BreakParent;
- }
- const Scope *getBreakParent() const {
- return const_cast<Scope*>(this)->getBreakParent();
- }
- Scope *getBlockParent() { return BlockParent; }
- const Scope *getBlockParent() const { return BlockParent; }
- Scope *getTemplateParamParent() { return TemplateParamParent; }
- const Scope *getTemplateParamParent() const { return TemplateParamParent; }
- /// Returns the depth of this scope. The translation-unit has scope depth 0.
- unsigned getDepth() const { return Depth; }
- /// Returns the number of function prototype scopes in this scope
- /// chain.
- unsigned getFunctionPrototypeDepth() const {
- return PrototypeDepth;
- }
- /// Return the number of parameters declared in this function
- /// prototype, increasing it by one for the next call.
- unsigned getNextFunctionPrototypeIndex() {
- assert(isFunctionPrototypeScope());
- return PrototypeIndex++;
- }
- using decl_range = llvm::iterator_range<DeclSetTy::iterator>;
- decl_range decls() const {
- return decl_range(DeclsInScope.begin(), DeclsInScope.end());
- }
- bool decl_empty() const { return DeclsInScope.empty(); }
- void AddDecl(Decl *D) {
- if (auto *VD = dyn_cast<VarDecl>(D))
- if (!isa<ParmVarDecl>(VD))
- ReturnSlots.insert(VD);
- DeclsInScope.insert(D);
- }
- void RemoveDecl(Decl *D) { DeclsInScope.erase(D); }
- void incrementMSManglingNumber() {
- if (Scope *MSLMP = getMSLastManglingParent()) {
- MSLMP->MSLastManglingNumber += 1;
- MSCurManglingNumber += 1;
- }
- }
- void decrementMSManglingNumber() {
- if (Scope *MSLMP = getMSLastManglingParent()) {
- MSLMP->MSLastManglingNumber -= 1;
- MSCurManglingNumber -= 1;
- }
- }
- unsigned getMSLastManglingNumber() const {
- if (const Scope *MSLMP = getMSLastManglingParent())
- return MSLMP->MSLastManglingNumber;
- return 1;
- }
- unsigned getMSCurManglingNumber() const {
- return MSCurManglingNumber;
- }
- /// isDeclScope - Return true if this is the scope that the specified decl is
- /// declared in.
- bool isDeclScope(const Decl *D) const { return DeclsInScope.contains(D); }
- /// Get the entity corresponding to this scope.
- DeclContext *getEntity() const {
- return isTemplateParamScope() ? nullptr : Entity;
- }
- /// Get the DeclContext in which to continue unqualified lookup after a
- /// lookup in this scope.
- DeclContext *getLookupEntity() const { return Entity; }
- void setEntity(DeclContext *E) {
- assert(!isTemplateParamScope() &&
- "entity associated with template param scope");
- Entity = E;
- }
- void setLookupEntity(DeclContext *E) { Entity = E; }
- /// Determine whether any unrecoverable errors have occurred within this
- /// scope. Note that this may return false even if the scope contains invalid
- /// declarations or statements, if the errors for those invalid constructs
- /// were suppressed because some prior invalid construct was referenced.
- bool hasUnrecoverableErrorOccurred() const {
- return ErrorTrap.hasUnrecoverableErrorOccurred();
- }
- /// isFunctionScope() - Return true if this scope is a function scope.
- bool isFunctionScope() const { return getFlags() & Scope::FnScope; }
- /// isClassScope - Return true if this scope is a class/struct/union scope.
- bool isClassScope() const { return getFlags() & Scope::ClassScope; }
- /// Determines whether this scope is between inheritance colon and the real
- /// class/struct definition.
- bool isClassInheritanceScope() const {
- return getFlags() & Scope::ClassInheritanceScope;
- }
- /// isInCXXInlineMethodScope - Return true if this scope is a C++ inline
- /// method scope or is inside one.
- bool isInCXXInlineMethodScope() const {
- if (const Scope *FnS = getFnParent()) {
- assert(FnS->getParent() && "TUScope not created?");
- return FnS->getParent()->isClassScope();
- }
- return false;
- }
- /// isInObjcMethodScope - Return true if this scope is, or is contained in, an
- /// Objective-C method body. Note that this method is not constant time.
- bool isInObjcMethodScope() const {
- for (const Scope *S = this; S; S = S->getParent()) {
- // If this scope is an objc method scope, then we succeed.
- if (S->getFlags() & ObjCMethodScope)
- return true;
- }
- return false;
- }
- /// isInObjcMethodOuterScope - Return true if this scope is an
- /// Objective-C method outer most body.
- bool isInObjcMethodOuterScope() const {
- if (const Scope *S = this) {
- // If this scope is an objc method scope, then we succeed.
- if (S->getFlags() & ObjCMethodScope)
- return true;
- }
- return false;
- }
- /// isTemplateParamScope - Return true if this scope is a C++
- /// template parameter scope.
- bool isTemplateParamScope() const {
- return getFlags() & Scope::TemplateParamScope;
- }
- /// isFunctionPrototypeScope - Return true if this scope is a
- /// function prototype scope.
- bool isFunctionPrototypeScope() const {
- return getFlags() & Scope::FunctionPrototypeScope;
- }
- /// isFunctionDeclarationScope - Return true if this scope is a
- /// function prototype scope.
- bool isFunctionDeclarationScope() const {
- return getFlags() & Scope::FunctionDeclarationScope;
- }
- /// isAtCatchScope - Return true if this scope is \@catch.
- bool isAtCatchScope() const {
- return getFlags() & Scope::AtCatchScope;
- }
- /// isCatchScope - Return true if this scope is a C++ catch statement.
- bool isCatchScope() const { return getFlags() & Scope::CatchScope; }
- /// isSwitchScope - Return true if this scope is a switch scope.
- bool isSwitchScope() const {
- for (const Scope *S = this; S; S = S->getParent()) {
- if (S->getFlags() & Scope::SwitchScope)
- return true;
- else if (S->getFlags() & (Scope::FnScope | Scope::ClassScope |
- Scope::BlockScope | Scope::TemplateParamScope |
- Scope::FunctionPrototypeScope |
- Scope::AtCatchScope | Scope::ObjCMethodScope))
- return false;
- }
- return false;
- }
- /// Determines whether this scope is the OpenMP directive scope
- bool isOpenMPDirectiveScope() const {
- return (getFlags() & Scope::OpenMPDirectiveScope);
- }
- /// Determine whether this scope is some OpenMP loop directive scope
- /// (for example, 'omp for', 'omp simd').
- bool isOpenMPLoopDirectiveScope() const {
- if (getFlags() & Scope::OpenMPLoopDirectiveScope) {
- assert(isOpenMPDirectiveScope() &&
- "OpenMP loop directive scope is not a directive scope");
- return true;
- }
- return false;
- }
- /// Determine whether this scope is (or is nested into) some OpenMP
- /// loop simd directive scope (for example, 'omp simd', 'omp for simd').
- bool isOpenMPSimdDirectiveScope() const {
- return getFlags() & Scope::OpenMPSimdDirectiveScope;
- }
- /// Determine whether this scope is a loop having OpenMP loop
- /// directive attached.
- bool isOpenMPLoopScope() const {
- const Scope *P = getParent();
- return P && P->isOpenMPLoopDirectiveScope();
- }
- /// Determine whether this scope is some OpenMP directive with
- /// order clause which specifies concurrent scope.
- bool isOpenMPOrderClauseScope() const {
- return getFlags() & Scope::OpenMPOrderClauseScope;
- }
- /// Determine whether this scope is a while/do/for statement, which can have
- /// continue statements embedded into it.
- bool isContinueScope() const {
- return getFlags() & ScopeFlags::ContinueScope;
- }
- /// Determine whether this scope is a C++ 'try' block.
- bool isTryScope() const { return getFlags() & Scope::TryScope; }
- /// Determine whether this scope is a function-level C++ try or catch scope.
- bool isFnTryCatchScope() const {
- return getFlags() & ScopeFlags::FnTryCatchScope;
- }
- /// Determine whether this scope is a SEH '__try' block.
- bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; }
- /// Determine whether this scope is a SEH '__except' block.
- bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; }
- /// Determine whether this scope is a compound statement scope.
- bool isCompoundStmtScope() const {
- return getFlags() & Scope::CompoundStmtScope;
- }
- /// Determine whether this scope is a controlling scope in a
- /// if/switch/while/for statement.
- bool isControlScope() const { return getFlags() & Scope::ControlScope; }
- /// Returns if rhs has a higher scope depth than this.
- ///
- /// The caller is responsible for calling this only if one of the two scopes
- /// is an ancestor of the other.
- bool Contains(const Scope& rhs) const { return Depth < rhs.Depth; }
- /// containedInPrototypeScope - Return true if this or a parent scope
- /// is a FunctionPrototypeScope.
- bool containedInPrototypeScope() const;
- void PushUsingDirective(UsingDirectiveDecl *UDir) {
- UsingDirectives.push_back(UDir);
- }
- using using_directives_range =
- llvm::iterator_range<UsingDirectivesTy::iterator>;
- using_directives_range using_directives() {
- return using_directives_range(UsingDirectives.begin(),
- UsingDirectives.end());
- }
- void updateNRVOCandidate(VarDecl *VD);
- void applyNRVO();
- /// Init - This is used by the parser to implement scope caching.
- void Init(Scope *parent, unsigned flags);
- /// Sets up the specified scope flags and adjusts the scope state
- /// variables accordingly.
- void AddFlags(unsigned Flags);
- void dumpImpl(raw_ostream &OS) const;
- void dump() const;
- };
- } // namespace clang
- #endif // LLVM_CLANG_SEMA_SCOPE_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|