diff options
Diffstat (limited to 'clang-r353983/include/clang/AST/Decl.h')
| -rw-r--r-- | clang-r353983/include/clang/AST/Decl.h | 4340 |
1 files changed, 4340 insertions, 0 deletions
diff --git a/clang-r353983/include/clang/AST/Decl.h b/clang-r353983/include/clang/AST/Decl.h new file mode 100644 index 00000000..526e2107 --- /dev/null +++ b/clang-r353983/include/clang/AST/Decl.h @@ -0,0 +1,4340 @@ +//===- Decl.h - Classes for representing declarations -----------*- 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 Decl subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECL_H +#define LLVM_CLANG_AST_DECL_H + +#include "clang/AST/APValue.h" +#include "clang/AST/ASTContextAllocate.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Redeclarable.h" +#include "clang/AST/Type.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Linkage.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/PragmaKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/Visibility.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <string> +#include <utility> + +namespace clang { + +class ASTContext; +struct ASTTemplateArgumentListInfo; +class Attr; +class CompoundStmt; +class DependentFunctionTemplateSpecializationInfo; +class EnumDecl; +class Expr; +class FunctionTemplateDecl; +class FunctionTemplateSpecializationInfo; +class LabelStmt; +class MemberSpecializationInfo; +class Module; +class NamespaceDecl; +class ParmVarDecl; +class RecordDecl; +class Stmt; +class StringLiteral; +class TagDecl; +class TemplateArgumentList; +class TemplateArgumentListInfo; +class TemplateParameterList; +class TypeAliasTemplateDecl; +class TypeLoc; +class UnresolvedSetImpl; +class VarTemplateDecl; + +/// A container of type source information. +/// +/// A client can read the relevant info using TypeLoc wrappers, e.g: +/// @code +/// TypeLoc TL = TypeSourceInfo->getTypeLoc(); +/// TL.getBeginLoc().print(OS, SrcMgr); +/// @endcode +class alignas(8) TypeSourceInfo { + // Contains a memory block after the class, used for type source information, + // allocated by ASTContext. + friend class ASTContext; + + QualType Ty; + + TypeSourceInfo(QualType ty) : Ty(ty) {} + +public: + /// Return the type wrapped by this type source info. + QualType getType() const { return Ty; } + + /// Return the TypeLoc wrapper for the type source info. + TypeLoc getTypeLoc() const; // implemented in TypeLoc.h + + /// Override the type stored in this TypeSourceInfo. Use with caution! + void overrideType(QualType T) { Ty = T; } +}; + +/// The top declaration context. +class TranslationUnitDecl : public Decl, public DeclContext { + ASTContext &Ctx; + + /// The (most recently entered) anonymous namespace for this + /// translation unit, if one has been created. + NamespaceDecl *AnonymousNamespace = nullptr; + + explicit TranslationUnitDecl(ASTContext &ctx); + + virtual void anchor(); + +public: + ASTContext &getASTContext() const { return Ctx; } + + NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; } + void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; } + + static TranslationUnitDecl *Create(ASTContext &C); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TranslationUnit; } + static DeclContext *castToDeclContext(const TranslationUnitDecl *D) { + return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D)); + } + static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TranslationUnitDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// Represents a `#pragma comment` line. Always a child of +/// TranslationUnitDecl. +class PragmaCommentDecl final + : public Decl, + private llvm::TrailingObjects<PragmaCommentDecl, char> { + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; + + PragmaMSCommentKind CommentKind; + + PragmaCommentDecl(TranslationUnitDecl *TU, SourceLocation CommentLoc, + PragmaMSCommentKind CommentKind) + : Decl(PragmaComment, TU, CommentLoc), CommentKind(CommentKind) {} + + virtual void anchor(); + +public: + static PragmaCommentDecl *Create(const ASTContext &C, TranslationUnitDecl *DC, + SourceLocation CommentLoc, + PragmaMSCommentKind CommentKind, + StringRef Arg); + static PragmaCommentDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned ArgSize); + + PragmaMSCommentKind getCommentKind() const { return CommentKind; } + + StringRef getArg() const { return getTrailingObjects<char>(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == PragmaComment; } +}; + +/// Represents a `#pragma detect_mismatch` line. Always a child of +/// TranslationUnitDecl. +class PragmaDetectMismatchDecl final + : public Decl, + private llvm::TrailingObjects<PragmaDetectMismatchDecl, char> { + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; + + size_t ValueStart; + + PragmaDetectMismatchDecl(TranslationUnitDecl *TU, SourceLocation Loc, + size_t ValueStart) + : Decl(PragmaDetectMismatch, TU, Loc), ValueStart(ValueStart) {} + + virtual void anchor(); + +public: + static PragmaDetectMismatchDecl *Create(const ASTContext &C, + TranslationUnitDecl *DC, + SourceLocation Loc, StringRef Name, + StringRef Value); + static PragmaDetectMismatchDecl * + CreateDeserialized(ASTContext &C, unsigned ID, unsigned NameValueSize); + + StringRef getName() const { return getTrailingObjects<char>(); } + StringRef getValue() const { return getTrailingObjects<char>() + ValueStart; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == PragmaDetectMismatch; } +}; + +/// Declaration context for names declared as extern "C" in C++. This +/// is neither the semantic nor lexical context for such declarations, but is +/// used to check for conflicts with other extern "C" declarations. Example: +/// +/// \code +/// namespace N { extern "C" void f(); } // #1 +/// void N::f() {} // #2 +/// namespace M { extern "C" void f(); } // #3 +/// \endcode +/// +/// The semantic context of #1 is namespace N and its lexical context is the +/// LinkageSpecDecl; the semantic context of #2 is namespace N and its lexical +/// context is the TU. However, both declarations are also visible in the +/// extern "C" context. +/// +/// The declaration at #3 finds it is a redeclaration of \c N::f through +/// lookup in the extern "C" context. +class ExternCContextDecl : public Decl, public DeclContext { + explicit ExternCContextDecl(TranslationUnitDecl *TU) + : Decl(ExternCContext, TU, SourceLocation()), + DeclContext(ExternCContext) {} + + virtual void anchor(); + +public: + static ExternCContextDecl *Create(const ASTContext &C, + TranslationUnitDecl *TU); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ExternCContext; } + static DeclContext *castToDeclContext(const ExternCContextDecl *D) { + return static_cast<DeclContext *>(const_cast<ExternCContextDecl*>(D)); + } + static ExternCContextDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ExternCContextDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// This represents a decl that may have a name. Many decls have names such +/// as ObjCMethodDecl, but not \@class, etc. +/// +/// Note that not every NamedDecl is actually named (e.g., a struct might +/// be anonymous), and not every name is an identifier. +class NamedDecl : public Decl { + /// The name of this declaration, which is typically a normal + /// identifier but may also be a special kind of name (C++ + /// constructor, Objective-C selector, etc.) + DeclarationName Name; + + virtual void anchor(); + +private: + NamedDecl *getUnderlyingDeclImpl() LLVM_READONLY; + +protected: + NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N) + : Decl(DK, DC, L), Name(N) {} + +public: + /// Get the identifier that names this declaration, if there is one. + /// + /// This will return NULL if this declaration has no name (e.g., for + /// an unnamed class) or if the name is a special name (C++ constructor, + /// Objective-C selector, etc.). + IdentifierInfo *getIdentifier() const { return Name.getAsIdentifierInfo(); } + + /// Get the name of identifier for this declaration as a StringRef. + /// + /// This requires that the declaration have a name and that it be a simple + /// identifier. + StringRef getName() const { + assert(Name.isIdentifier() && "Name is not a simple identifier"); + return getIdentifier() ? getIdentifier()->getName() : ""; + } + + /// Get a human-readable name for the declaration, even if it is one of the + /// special kinds of names (C++ constructor, Objective-C selector, etc). + /// + /// Creating this name requires expensive string manipulation, so it should + /// be called only when performance doesn't matter. For simple declarations, + /// getNameAsCString() should suffice. + // + // FIXME: This function should be renamed to indicate that it is not just an + // alternate form of getName(), and clients should move as appropriate. + // + // FIXME: Deprecated, move clients to getName(). + std::string getNameAsString() const { return Name.getAsString(); } + + virtual void printName(raw_ostream &os) const; + + /// Get the actual, stored name of the declaration, which may be a special + /// name. + DeclarationName getDeclName() const { return Name; } + + /// Set the name of this declaration. + void setDeclName(DeclarationName N) { Name = N; } + + /// Returns a human-readable qualified name for this declaration, like + /// A::B::i, for i being member of namespace A::B. + /// + /// If the declaration is not a member of context which can be named (record, + /// namespace), it will return the same result as printName(). + /// + /// Creating this name is expensive, so it should be called only when + /// performance doesn't matter. + void printQualifiedName(raw_ostream &OS) const; + void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy) const; + + // FIXME: Remove string version. + std::string getQualifiedNameAsString() const; + + /// Appends a human-readable name for this declaration into the given stream. + /// + /// This is the method invoked by Sema when displaying a NamedDecl + /// in a diagnostic. It does not necessarily produce the same + /// result as printName(); for example, class template + /// specializations are printed with their template arguments. + virtual void getNameForDiagnostic(raw_ostream &OS, + const PrintingPolicy &Policy, + bool Qualified) const; + + /// Determine whether this declaration, if known to be well-formed within + /// its context, will replace the declaration OldD if introduced into scope. + /// + /// A declaration will replace another declaration if, for example, it is + /// a redeclaration of the same variable or function, but not if it is a + /// declaration of a different kind (function vs. class) or an overloaded + /// function. + /// + /// \param IsKnownNewer \c true if this declaration is known to be newer + /// than \p OldD (for instance, if this declaration is newly-created). + bool declarationReplaces(NamedDecl *OldD, bool IsKnownNewer = true) const; + + /// Determine whether this declaration has linkage. + bool hasLinkage() const; + + using Decl::isModulePrivate; + using Decl::setModulePrivate; + + /// Determine whether this declaration is a C++ class member. + bool isCXXClassMember() const { + const DeclContext *DC = getDeclContext(); + + // C++0x [class.mem]p1: + // The enumerators of an unscoped enumeration defined in + // the class are members of the class. + if (isa<EnumDecl>(DC)) + DC = DC->getRedeclContext(); + + return DC->isRecord(); + } + + /// Determine whether the given declaration is an instance member of + /// a C++ class. + bool isCXXInstanceMember() const; + + /// Determine what kind of linkage this entity has. + /// + /// This is not the linkage as defined by the standard or the codegen notion + /// of linkage. It is just an implementation detail that is used to compute + /// those. + Linkage getLinkageInternal() const; + + /// Get the linkage from a semantic point of view. Entities in + /// anonymous namespaces are external (in c++98). + Linkage getFormalLinkage() const { + return clang::getFormalLinkage(getLinkageInternal()); + } + + /// True if this decl has external linkage. + bool hasExternalFormalLinkage() const { + return isExternalFormalLinkage(getLinkageInternal()); + } + + bool isExternallyVisible() const { + return clang::isExternallyVisible(getLinkageInternal()); + } + + /// Determine whether this declaration can be redeclared in a + /// different translation unit. + bool isExternallyDeclarable() const { + return isExternallyVisible() && !getOwningModuleForLinkage(); + } + + /// Determines the visibility of this entity. + Visibility getVisibility() const { + return getLinkageAndVisibility().getVisibility(); + } + + /// Determines the linkage and visibility of this entity. + LinkageInfo getLinkageAndVisibility() const; + + /// Kinds of explicit visibility. + enum ExplicitVisibilityKind { + /// Do an LV computation for, ultimately, a type. + /// Visibility may be restricted by type visibility settings and + /// the visibility of template arguments. + VisibilityForType, + + /// Do an LV computation for, ultimately, a non-type declaration. + /// Visibility may be restricted by value visibility settings and + /// the visibility of template arguments. + VisibilityForValue + }; + + /// If visibility was explicitly specified for this + /// declaration, return that visibility. + Optional<Visibility> + getExplicitVisibility(ExplicitVisibilityKind kind) const; + + /// True if the computed linkage is valid. Used for consistency + /// checking. Should always return true. + bool isLinkageValid() const; + + /// True if something has required us to compute the linkage + /// of this declaration. + /// + /// Language features which can retroactively change linkage (like a + /// typedef name for linkage purposes) may need to consider this, + /// but hopefully only in transitory ways during parsing. + bool hasLinkageBeenComputed() const { + return hasCachedLinkage(); + } + + /// Looks through UsingDecls and ObjCCompatibleAliasDecls for + /// the underlying named decl. + NamedDecl *getUnderlyingDecl() { + // Fast-path the common case. + if (this->getKind() != UsingShadow && + this->getKind() != ConstructorUsingShadow && + this->getKind() != ObjCCompatibleAlias && + this->getKind() != NamespaceAlias) + return this; + + return getUnderlyingDeclImpl(); + } + const NamedDecl *getUnderlyingDecl() const { + return const_cast<NamedDecl*>(this)->getUnderlyingDecl(); + } + + NamedDecl *getMostRecentDecl() { + return cast<NamedDecl>(static_cast<Decl *>(this)->getMostRecentDecl()); + } + const NamedDecl *getMostRecentDecl() const { + return const_cast<NamedDecl*>(this)->getMostRecentDecl(); + } + + ObjCStringFormatFamily getObjCFStringFormattingFamily() const; + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; } +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) { + ND.printName(OS); + return OS; +} + +/// Represents the declaration of a label. Labels also have a +/// corresponding LabelStmt, which indicates the position that the label was +/// defined at. For normal labels, the location of the decl is the same as the +/// location of the statement. For GNU local labels (__label__), the decl +/// location is where the __label__ is. +class LabelDecl : public NamedDecl { + LabelStmt *TheStmt; + StringRef MSAsmName; + bool MSAsmNameResolved = false; + + /// For normal labels, this is the same as the main declaration + /// label, i.e., the location of the identifier; for GNU local labels, + /// this is the location of the __label__ keyword. + SourceLocation LocStart; + + LabelDecl(DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II, + LabelStmt *S, SourceLocation StartL) + : NamedDecl(Label, DC, IdentL, II), TheStmt(S), LocStart(StartL) {} + + void anchor() override; + +public: + static LabelDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II); + static LabelDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II, + SourceLocation GnuLabelL); + static LabelDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + LabelStmt *getStmt() const { return TheStmt; } + void setStmt(LabelStmt *T) { TheStmt = T; } + + bool isGnuLocal() const { return LocStart != getLocation(); } + void setLocStart(SourceLocation L) { LocStart = L; } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(LocStart, getLocation()); + } + + bool isMSAsmLabel() const { return !MSAsmName.empty(); } + bool isResolvedMSAsmLabel() const { return isMSAsmLabel() && MSAsmNameResolved; } + void setMSAsmLabel(StringRef Name); + StringRef getMSAsmLabel() const { return MSAsmName; } + void setMSAsmLabelResolved() { MSAsmNameResolved = true; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Label; } +}; + +/// Represent a C++ namespace. +class NamespaceDecl : public NamedDecl, public DeclContext, + public Redeclarable<NamespaceDecl> +{ + /// The starting location of the source range, pointing + /// to either the namespace or the inline keyword. + SourceLocation LocStart; + + /// The ending location of the source range. + SourceLocation RBraceLoc; + + /// A pointer to either the anonymous namespace that lives just inside + /// this namespace or to the first namespace in the chain (the latter case + /// only when this is not the first in the chain), along with a + /// boolean value indicating whether this is an inline namespace. + llvm::PointerIntPair<NamespaceDecl *, 1, bool> AnonOrFirstNamespaceAndInline; + + NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, NamespaceDecl *PrevDecl); + + using redeclarable_base = Redeclarable<NamespaceDecl>; + + NamespaceDecl *getNextRedeclarationImpl() override; + NamespaceDecl *getPreviousDeclImpl() override; + NamespaceDecl *getMostRecentDeclImpl() override; + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + + static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, + bool Inline, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + NamespaceDecl *PrevDecl); + + static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + /// Returns true if this is an anonymous namespace declaration. + /// + /// For example: + /// \code + /// namespace { + /// ... + /// }; + /// \endcode + /// q.v. C++ [namespace.unnamed] + bool isAnonymousNamespace() const { + return !getIdentifier(); + } + + /// Returns true if this is an inline namespace declaration. + bool isInline() const { + return AnonOrFirstNamespaceAndInline.getInt(); + } + + /// Set whether this is an inline namespace declaration. + void setInline(bool Inline) { + AnonOrFirstNamespaceAndInline.setInt(Inline); + } + + /// Get the original (first) namespace declaration. + NamespaceDecl *getOriginalNamespace(); + + /// Get the original (first) namespace declaration. + const NamespaceDecl *getOriginalNamespace() const; + + /// Return true if this declaration is an original (first) declaration + /// of the namespace. This is false for non-original (subsequent) namespace + /// declarations and anonymous namespaces. + bool isOriginalNamespace() const; + + /// Retrieve the anonymous namespace nested inside this namespace, + /// if any. + NamespaceDecl *getAnonymousNamespace() const { + return getOriginalNamespace()->AnonOrFirstNamespaceAndInline.getPointer(); + } + + void setAnonymousNamespace(NamespaceDecl *D) { + getOriginalNamespace()->AnonOrFirstNamespaceAndInline.setPointer(D); + } + + /// Retrieves the canonical declaration of this namespace. + NamespaceDecl *getCanonicalDecl() override { + return getOriginalNamespace(); + } + const NamespaceDecl *getCanonicalDecl() const { + return getOriginalNamespace(); + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(LocStart, RBraceLoc); + } + + SourceLocation getBeginLoc() const LLVM_READONLY { return LocStart; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setLocStart(SourceLocation L) { LocStart = L; } + void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Namespace; } + static DeclContext *castToDeclContext(const NamespaceDecl *D) { + return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D)); + } + static NamespaceDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<NamespaceDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// Represent the declaration of a variable (in which case it is +/// an lvalue) a function (in which case it is a function designator) or +/// an enum constant. +class ValueDecl : public NamedDecl { + QualType DeclType; + + void anchor() override; + +protected: + ValueDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T) + : NamedDecl(DK, DC, L, N), DeclType(T) {} + +public: + QualType getType() const { return DeclType; } + void setType(QualType newType) { DeclType = newType; } + + /// Determine whether this symbol is weakly-imported, + /// or declared with the weak or weak-ref attr. + bool isWeak() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; } +}; + +/// A struct with extended info about a syntactic +/// name qualifier, to be used for the case of out-of-line declarations. +struct QualifierInfo { + NestedNameSpecifierLoc QualifierLoc; + + /// The number of "outer" template parameter lists. + /// The count includes all of the template parameter lists that were matched + /// against the template-ids occurring into the NNS and possibly (in the + /// case of an explicit specialization) a final "template <>". + unsigned NumTemplParamLists = 0; + + /// A new-allocated array of size NumTemplParamLists, + /// containing pointers to the "outer" template parameter lists. + /// It includes all of the template parameter lists that were matched + /// against the template-ids occurring into the NNS and possibly (in the + /// case of an explicit specialization) a final "template <>". + TemplateParameterList** TemplParamLists = nullptr; + + QualifierInfo() = default; + QualifierInfo(const QualifierInfo &) = delete; + QualifierInfo& operator=(const QualifierInfo &) = delete; + + /// Sets info about "outer" template parameter lists. + void setTemplateParameterListsInfo(ASTContext &Context, + ArrayRef<TemplateParameterList *> TPLists); +}; + +/// Represents a ValueDecl that came out of a declarator. +/// Contains type source information through TypeSourceInfo. +class DeclaratorDecl : public ValueDecl { + // A struct representing both a TInfo and a syntactic qualifier, + // to be used for the (uncommon) case of out-of-line declarations. + struct ExtInfo : public QualifierInfo { + TypeSourceInfo *TInfo; + }; + + llvm::PointerUnion<TypeSourceInfo *, ExtInfo *> DeclInfo; + + /// The start of the source range for this declaration, + /// ignoring outer template declarations. + SourceLocation InnerLocStart; + + bool hasExtInfo() const { return DeclInfo.is<ExtInfo*>(); } + ExtInfo *getExtInfo() { return DeclInfo.get<ExtInfo*>(); } + const ExtInfo *getExtInfo() const { return DeclInfo.get<ExtInfo*>(); } + +protected: + DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, + SourceLocation StartL) + : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo), InnerLocStart(StartL) {} + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + + TypeSourceInfo *getTypeSourceInfo() const { + return hasExtInfo() + ? getExtInfo()->TInfo + : DeclInfo.get<TypeSourceInfo*>(); + } + + void setTypeSourceInfo(TypeSourceInfo *TI) { + if (hasExtInfo()) + getExtInfo()->TInfo = TI; + else + DeclInfo = TI; + } + + /// Return start of source range ignoring outer template declarations. + SourceLocation getInnerLocStart() const { return InnerLocStart; } + void setInnerLocStart(SourceLocation L) { InnerLocStart = L; } + + /// Return start of source range taking into account any outer template + /// declarations. + SourceLocation getOuterLocStart() const; + + SourceRange getSourceRange() const override LLVM_READONLY; + + SourceLocation getBeginLoc() const LLVM_READONLY { + return getOuterLocStart(); + } + + /// Retrieve the nested-name-specifier that qualifies the name of this + /// declaration, if it was present in the source. + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() + : nullptr; + } + + /// Retrieve the nested-name-specifier (with source-location + /// information) that qualifies the name of this declaration, if it was + /// present in the source. + NestedNameSpecifierLoc getQualifierLoc() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc + : NestedNameSpecifierLoc(); + } + + void setQualifierInfo(NestedNameSpecifierLoc QualifierLoc); + + unsigned getNumTemplateParameterLists() const { + return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; + } + + TemplateParameterList *getTemplateParameterList(unsigned index) const { + assert(index < getNumTemplateParameterLists()); + return getExtInfo()->TemplParamLists[index]; + } + + void setTemplateParameterListsInfo(ASTContext &Context, + ArrayRef<TemplateParameterList *> TPLists); + + SourceLocation getTypeSpecStartLoc() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstDeclarator && K <= lastDeclarator; + } +}; + +/// Structure used to store a statement, the constant value to +/// which it was evaluated (if any), and whether or not the statement +/// is an integral constant expression (if known). +struct EvaluatedStmt { + /// Whether this statement was already evaluated. + bool WasEvaluated : 1; + + /// Whether this statement is being evaluated. + bool IsEvaluating : 1; + + /// Whether we already checked whether this statement was an + /// integral constant expression. + bool CheckedICE : 1; + + /// Whether we are checking whether this statement is an + /// integral constant expression. + bool CheckingICE : 1; + + /// Whether this statement is an integral constant expression, + /// or in C++11, whether the statement is a constant expression. Only + /// valid if CheckedICE is true. + bool IsICE : 1; + + Stmt *Value; + APValue Evaluated; + + EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false), + CheckingICE(false), IsICE(false) {} + +}; + +/// Represents a variable declaration or definition. +class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> { +public: + /// Initialization styles. + enum InitializationStyle { + /// C-style initialization with assignment + CInit, + + /// Call-style initialization (C++98) + CallInit, + + /// Direct list-initialization (C++11) + ListInit + }; + + /// Kinds of thread-local storage. + enum TLSKind { + /// Not a TLS variable. + TLS_None, + + /// TLS with a known-constant initializer. + TLS_Static, + + /// TLS with a dynamic initializer. + TLS_Dynamic + }; + + /// Return the string used to specify the storage class \p SC. + /// + /// It is illegal to call this function with SC == None. + static const char *getStorageClassSpecifierString(StorageClass SC); + +protected: + // A pointer union of Stmt * and EvaluatedStmt *. When an EvaluatedStmt, we + // have allocated the auxiliary struct of information there. + // + // TODO: It is a bit unfortunate to use a PointerUnion inside the VarDecl for + // this as *many* VarDecls are ParmVarDecls that don't have default + // arguments. We could save some space by moving this pointer union to be + // allocated in trailing space when necessary. + using InitType = llvm::PointerUnion<Stmt *, EvaluatedStmt *>; + + /// The initializer for this variable or, for a ParmVarDecl, the + /// C++ default argument. + mutable InitType Init; + +private: + friend class ASTDeclReader; + friend class ASTNodeImporter; + friend class StmtIteratorBase; + + class VarDeclBitfields { + friend class ASTDeclReader; + friend class VarDecl; + + unsigned SClass : 3; + unsigned TSCSpec : 2; + unsigned InitStyle : 2; + + /// Whether this variable is an ARC pseudo-__strong variable; see + /// isARCPseudoStrong() for details. + unsigned ARCPseudoStrong : 1; + }; + enum { NumVarDeclBits = 8 }; + +protected: + enum { NumParameterIndexBits = 8 }; + + enum DefaultArgKind { + DAK_None, + DAK_Unparsed, + DAK_Uninstantiated, + DAK_Normal + }; + + class ParmVarDeclBitfields { + friend class ASTDeclReader; + friend class ParmVarDecl; + + unsigned : NumVarDeclBits; + + /// Whether this parameter inherits a default argument from a + /// prior declaration. + unsigned HasInheritedDefaultArg : 1; + + /// Describes the kind of default argument for this parameter. By default + /// this is none. If this is normal, then the default argument is stored in + /// the \c VarDecl initializer expression unless we were unable to parse + /// (even an invalid) expression for the default argument. + unsigned DefaultArgKind : 2; + + /// Whether this parameter undergoes K&R argument promotion. + unsigned IsKNRPromoted : 1; + + /// Whether this parameter is an ObjC method parameter or not. + unsigned IsObjCMethodParam : 1; + + /// If IsObjCMethodParam, a Decl::ObjCDeclQualifier. + /// Otherwise, the number of function parameter scopes enclosing + /// the function parameter scope in which this parameter was + /// declared. + unsigned ScopeDepthOrObjCQuals : 7; + + /// The number of parameters preceding this parameter in the + /// function parameter scope in which it was declared. + unsigned ParameterIndex : NumParameterIndexBits; + }; + + class NonParmVarDeclBitfields { + friend class ASTDeclReader; + friend class ImplicitParamDecl; + friend class VarDecl; + + unsigned : NumVarDeclBits; + + // FIXME: We need something similar to CXXRecordDecl::DefinitionData. + /// Whether this variable is a definition which was demoted due to + /// module merge. + unsigned IsThisDeclarationADemotedDefinition : 1; + + /// Whether this variable is the exception variable in a C++ catch + /// or an Objective-C @catch statement. + unsigned ExceptionVar : 1; + + /// Whether this local variable could be allocated in the return + /// slot of its function, enabling the named return value optimization + /// (NRVO). + unsigned NRVOVariable : 1; + + /// Whether this variable is the for-range-declaration in a C++0x + /// for-range statement. + unsigned CXXForRangeDecl : 1; + + /// Whether this variable is the for-in loop declaration in Objective-C. + unsigned ObjCForDecl : 1; + + /// Whether this variable is (C++1z) inline. + unsigned IsInline : 1; + + /// Whether this variable has (C++1z) inline explicitly specified. + unsigned IsInlineSpecified : 1; + + /// Whether this variable is (C++0x) constexpr. + unsigned IsConstexpr : 1; + + /// Whether this variable is the implicit variable for a lambda + /// init-capture. + unsigned IsInitCapture : 1; + + /// Whether this local extern variable's previous declaration was + /// declared in the same block scope. This controls whether we should merge + /// the type of this declaration with its previous declaration. + unsigned PreviousDeclInSameBlockScope : 1; + + /// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or + /// something else. + unsigned ImplicitParamKind : 3; + + unsigned EscapingByref : 1; + }; + + union { + unsigned AllBits; + VarDeclBitfields VarDeclBits; + ParmVarDeclBitfields ParmVarDeclBits; + NonParmVarDeclBitfields NonParmVarDeclBits; + }; + + VarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass SC); + + using redeclarable_base = Redeclarable<VarDecl>; + + VarDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + + VarDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + + VarDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + static VarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, + StorageClass S); + + static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Returns the storage class as written in the source. For the + /// computed linkage of symbol, see getLinkage. + StorageClass getStorageClass() const { + return (StorageClass) VarDeclBits.SClass; + } + void setStorageClass(StorageClass SC); + + void setTSCSpec(ThreadStorageClassSpecifier TSC) { + VarDeclBits.TSCSpec = TSC; + assert(VarDeclBits.TSCSpec == TSC && "truncation"); + } + ThreadStorageClassSpecifier getTSCSpec() const { + return static_cast<ThreadStorageClassSpecifier>(VarDeclBits.TSCSpec); + } + TLSKind getTLSKind() const; + + /// Returns true if a variable with function scope is a non-static local + /// variable. + bool hasLocalStorage() const { + if (getStorageClass() == SC_None) { + // OpenCL v1.2 s6.5.3: The __constant or constant address space name is + // used to describe variables allocated in global memory and which are + // accessed inside a kernel(s) as read-only variables. As such, variables + // in constant address space cannot have local storage. + if (getType().getAddressSpace() == LangAS::opencl_constant) + return false; + // Second check is for C++11 [dcl.stc]p4. + return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified; + } + + // Global Named Register (GNU extension) + if (getStorageClass() == SC_Register && !isLocalVarDeclOrParm()) + return false; + + // Return true for: Auto, Register. + // Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal. + + return getStorageClass() >= SC_Auto; + } + + /// Returns true if a variable with function scope is a static local + /// variable. + bool isStaticLocal() const { + return (getStorageClass() == SC_Static || + // C++11 [dcl.stc]p4 + (getStorageClass() == SC_None && getTSCSpec() == TSCS_thread_local)) + && !isFileVarDecl(); + } + + /// Returns true if a variable has extern or __private_extern__ + /// storage. + bool hasExternalStorage() const { + return getStorageClass() == SC_Extern || + getStorageClass() == SC_PrivateExtern; + } + + /// Returns true for all variables that do not have local storage. + /// + /// This includes all global variables as well as static variables declared + /// within a function. + bool hasGlobalStorage() const { return !hasLocalStorage(); } + + /// Get the storage duration of this variable, per C++ [basic.stc]. + StorageDuration getStorageDuration() const { + return hasLocalStorage() ? SD_Automatic : + getTSCSpec() ? SD_Thread : SD_Static; + } + + /// Compute the language linkage. + LanguageLinkage getLanguageLinkage() const; + + /// Determines whether this variable is a variable with external, C linkage. + bool isExternC() const; + + /// Determines whether this variable's context is, or is nested within, + /// a C++ extern "C" linkage spec. + bool isInExternCContext() const; + + /// Determines whether this variable's context is, or is nested within, + /// a C++ extern "C++" linkage spec. + bool isInExternCXXContext() const; + + /// Returns true for local variable declarations other than parameters. + /// Note that this includes static variables inside of functions. It also + /// includes variables inside blocks. + /// + /// void foo() { int x; static int y; extern int z; } + bool isLocalVarDecl() const { + if (getKind() != Decl::Var && getKind() != Decl::Decomposition) + return false; + if (const DeclContext *DC = getLexicalDeclContext()) + return DC->getRedeclContext()->isFunctionOrMethod(); + return false; + } + + /// Similar to isLocalVarDecl but also includes parameters. + bool isLocalVarDeclOrParm() const { + return isLocalVarDecl() || getKind() == Decl::ParmVar; + } + + /// Similar to isLocalVarDecl, but excludes variables declared in blocks. + bool isFunctionOrMethodVarDecl() const { + if (getKind() != Decl::Var && getKind() != Decl::Decomposition) + return false; + const DeclContext *DC = getLexicalDeclContext()->getRedeclContext(); + return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block; + } + + /// Determines whether this is a static data member. + /// + /// This will only be true in C++, and applies to, e.g., the + /// variable 'x' in: + /// \code + /// struct S { + /// static int x; + /// }; + /// \endcode + bool isStaticDataMember() const { + // If it wasn't static, it would be a FieldDecl. + return getKind() != Decl::ParmVar && getDeclContext()->isRecord(); + } + + VarDecl *getCanonicalDecl() override; + const VarDecl *getCanonicalDecl() const { + return const_cast<VarDecl*>(this)->getCanonicalDecl(); + } + + enum DefinitionKind { + /// This declaration is only a declaration. + DeclarationOnly, + + /// This declaration is a tentative definition. + TentativeDefinition, + + /// This declaration is definitely a definition. + Definition + }; + + /// Check whether this declaration is a definition. If this could be + /// a tentative definition (in C), don't check whether there's an overriding + /// definition. + DefinitionKind isThisDeclarationADefinition(ASTContext &) const; + DefinitionKind isThisDeclarationADefinition() const { + return isThisDeclarationADefinition(getASTContext()); + } + + /// Check whether this variable is defined in this translation unit. + DefinitionKind hasDefinition(ASTContext &) const; + DefinitionKind hasDefinition() const { + return hasDefinition(getASTContext()); + } + + /// Get the tentative definition that acts as the real definition in a TU. + /// Returns null if there is a proper definition available. + VarDecl *getActingDefinition(); + const VarDecl *getActingDefinition() const { + return const_cast<VarDecl*>(this)->getActingDefinition(); + } + + /// Get the real (not just tentative) definition for this declaration. + VarDecl *getDefinition(ASTContext &); + const VarDecl *getDefinition(ASTContext &C) const { + return const_cast<VarDecl*>(this)->getDefinition(C); + } + VarDecl *getDefinition() { + return getDefinition(getASTContext()); + } + const VarDecl *getDefinition() const { + return const_cast<VarDecl*>(this)->getDefinition(); + } + + /// Determine whether this is or was instantiated from an out-of-line + /// definition of a static data member. + bool isOutOfLine() const override; + + /// Returns true for file scoped variable declaration. + bool isFileVarDecl() const { + Kind K = getKind(); + if (K == ParmVar || K == ImplicitParam) + return false; + + if (getLexicalDeclContext()->getRedeclContext()->isFileContext()) + return true; + + if (isStaticDataMember()) + return true; + + return false; + } + + /// Get the initializer for this variable, no matter which + /// declaration it is attached to. + const Expr *getAnyInitializer() const { + const VarDecl *D; + return getAnyInitializer(D); + } + + /// Get the initializer for this variable, no matter which + /// declaration it is attached to. Also get that declaration. + const Expr *getAnyInitializer(const VarDecl *&D) const; + + bool hasInit() const; + const Expr *getInit() const { + return const_cast<VarDecl *>(this)->getInit(); + } + Expr *getInit(); + + /// Retrieve the address of the initializer expression. + Stmt **getInitAddress(); + + void setInit(Expr *I); + + /// Determine whether this variable's value can be used in a + /// constant expression, according to the relevant language standard. + /// This only checks properties of the declaration, and does not check + /// whether the initializer is in fact a constant expression. + bool isUsableInConstantExpressions(ASTContext &C) const; + + EvaluatedStmt *ensureEvaluatedStmt() const; + + /// Attempt to evaluate the value of the initializer attached to this + /// declaration, and produce notes explaining why it cannot be evaluated or is + /// not a constant expression. Returns a pointer to the value if evaluation + /// succeeded, 0 otherwise. + APValue *evaluateValue() const; + APValue *evaluateValue(SmallVectorImpl<PartialDiagnosticAt> &Notes) const; + + /// Return the already-evaluated value of this variable's + /// initializer, or NULL if the value is not yet known. Returns pointer + /// to untyped APValue if the value could not be evaluated. + APValue *getEvaluatedValue() const; + + /// Determines whether it is already known whether the + /// initializer is an integral constant expression or not. + bool isInitKnownICE() const; + + /// Determines whether the initializer is an integral constant + /// expression, or in C++11, whether the initializer is a constant + /// expression. + /// + /// \pre isInitKnownICE() + bool isInitICE() const; + + /// Determine whether the value of the initializer attached to this + /// declaration is an integral constant expression. + bool checkInitIsICE() const; + + void setInitStyle(InitializationStyle Style) { + VarDeclBits.InitStyle = Style; + } + + /// The style of initialization for this declaration. + /// + /// C-style initialization is "int x = 1;". Call-style initialization is + /// a C++98 direct-initializer, e.g. "int x(1);". The Init expression will be + /// the expression inside the parens or a "ClassType(a,b,c)" class constructor + /// expression for class types. List-style initialization is C++11 syntax, + /// e.g. "int x{1};". Clients can distinguish between different forms of + /// initialization by checking this value. In particular, "int x = {1};" is + /// C-style, "int x({1})" is call-style, and "int x{1};" is list-style; the + /// Init expression in all three cases is an InitListExpr. + InitializationStyle getInitStyle() const { + return static_cast<InitializationStyle>(VarDeclBits.InitStyle); + } + + /// Whether the initializer is a direct-initializer (list or call). + bool isDirectInit() const { + return getInitStyle() != CInit; + } + + /// If this definition should pretend to be a declaration. + bool isThisDeclarationADemotedDefinition() const { + return isa<ParmVarDecl>(this) ? false : + NonParmVarDeclBits.IsThisDeclarationADemotedDefinition; + } + + /// This is a definition which should be demoted to a declaration. + /// + /// In some cases (mostly module merging) we can end up with two visible + /// definitions one of which needs to be demoted to a declaration to keep + /// the AST invariants. + void demoteThisDefinitionToDeclaration() { + assert(isThisDeclarationADefinition() && "Not a definition!"); + assert(!isa<ParmVarDecl>(this) && "Cannot demote ParmVarDecls!"); + NonParmVarDeclBits.IsThisDeclarationADemotedDefinition = 1; + } + + /// Determine whether this variable is the exception variable in a + /// C++ catch statememt or an Objective-C \@catch statement. + bool isExceptionVariable() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.ExceptionVar; + } + void setExceptionVariable(bool EV) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.ExceptionVar = EV; + } + + /// Determine whether this local variable can be used with the named + /// return value optimization (NRVO). + /// + /// The named return value optimization (NRVO) works by marking certain + /// non-volatile local variables of class type as NRVO objects. These + /// locals can be allocated within the return slot of their containing + /// function, in which case there is no need to copy the object to the + /// return slot when returning from the function. Within the function body, + /// each return that returns the NRVO object will have this variable as its + /// NRVO candidate. + bool isNRVOVariable() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.NRVOVariable; + } + void setNRVOVariable(bool NRVO) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.NRVOVariable = NRVO; + } + + /// Determine whether this variable is the for-range-declaration in + /// a C++0x for-range statement. + bool isCXXForRangeDecl() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.CXXForRangeDecl; + } + void setCXXForRangeDecl(bool FRD) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.CXXForRangeDecl = FRD; + } + + /// Determine whether this variable is a for-loop declaration for a + /// for-in statement in Objective-C. + bool isObjCForDecl() const { + return NonParmVarDeclBits.ObjCForDecl; + } + + void setObjCForDecl(bool FRD) { + NonParmVarDeclBits.ObjCForDecl = FRD; + } + + /// Determine whether this variable is an ARC pseudo-__strong variable. A + /// pseudo-__strong variable has a __strong-qualified type but does not + /// actually retain the object written into it. Generally such variables are + /// also 'const' for safety. There are 3 cases where this will be set, 1) if + /// the variable is annotated with the objc_externally_retained attribute, 2) + /// if its 'self' in a non-init method, or 3) if its the variable in an for-in + /// loop. + bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; } + void setARCPseudoStrong(bool PS) { VarDeclBits.ARCPseudoStrong = PS; } + + /// Whether this variable is (C++1z) inline. + bool isInline() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsInline; + } + bool isInlineSpecified() const { + return isa<ParmVarDecl>(this) ? false + : NonParmVarDeclBits.IsInlineSpecified; + } + void setInlineSpecified() { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.IsInline = true; + NonParmVarDeclBits.IsInlineSpecified = true; + } + void setImplicitlyInline() { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.IsInline = true; + } + + /// Whether this variable is (C++11) constexpr. + bool isConstexpr() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsConstexpr; + } + void setConstexpr(bool IC) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.IsConstexpr = IC; + } + + /// Whether this variable is the implicit variable for a lambda init-capture. + bool isInitCapture() const { + return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsInitCapture; + } + void setInitCapture(bool IC) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.IsInitCapture = IC; + } + + /// Whether this local extern variable declaration's previous declaration + /// was declared in the same block scope. Only correct in C++. + bool isPreviousDeclInSameBlockScope() const { + return isa<ParmVarDecl>(this) + ? false + : NonParmVarDeclBits.PreviousDeclInSameBlockScope; + } + void setPreviousDeclInSameBlockScope(bool Same) { + assert(!isa<ParmVarDecl>(this)); + NonParmVarDeclBits.PreviousDeclInSameBlockScope = Same; + } + + /// Indicates the capture is a __block variable that is captured by a block + /// that can potentially escape (a block for which BlockDecl::doesNotEscape + /// returns false). + bool isEscapingByref() const; + + /// Indicates the capture is a __block variable that is never captured by an + /// escaping block. + bool isNonEscapingByref() const; + + void setEscapingByref() { + NonParmVarDeclBits.EscapingByref = true; + } + + /// Retrieve the variable declaration from which this variable could + /// be instantiated, if it is an instantiation (rather than a non-template). + VarDecl *getTemplateInstantiationPattern() const; + + /// If this variable is an instantiated static data member of a + /// class template specialization, returns the templated static data member + /// from which it was instantiated. + VarDecl *getInstantiatedFromStaticDataMember() const; + + /// If this variable is an instantiation of a variable template or a + /// static data member of a class template, determine what kind of + /// template specialization or instantiation this is. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// If this variable is an instantiation of a variable template or a + /// static data member of a class template, determine its point of + /// instantiation. + SourceLocation getPointOfInstantiation() const; + + /// If this variable is an instantiation of a static data member of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// For a static data member that was instantiated from a static + /// data member of a class template, set the template specialiation kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// Specify that this variable is an instantiation of the + /// static data member VD. + void setInstantiationOfStaticDataMember(VarDecl *VD, + TemplateSpecializationKind TSK); + + /// Retrieves the variable template that is described by this + /// variable declaration. + /// + /// Every variable template is represented as a VarTemplateDecl and a + /// VarDecl. The former contains template properties (such as + /// the template parameter lists) while the latter contains the + /// actual description of the template's + /// contents. VarTemplateDecl::getTemplatedDecl() retrieves the + /// VarDecl that from a VarTemplateDecl, while + /// getDescribedVarTemplate() retrieves the VarTemplateDecl from + /// a VarDecl. + VarTemplateDecl *getDescribedVarTemplate() const; + + void setDescribedVarTemplate(VarTemplateDecl *Template); + + // Is this variable known to have a definition somewhere in the complete + // program? This may be true even if the declaration has internal linkage and + // has no definition within this source file. + bool isKnownToBeDefined() const; + + /// Do we need to emit an exit-time destructor for this variable? + bool isNoDestroy(const ASTContext &) const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } +}; + +class ImplicitParamDecl : public VarDecl { + void anchor() override; + +public: + /// Defines the kind of the implicit parameter: is this an implicit parameter + /// with pointer to 'this', 'self', '_cmd', virtual table pointers, captured + /// context or something else. + enum ImplicitParamKind : unsigned { + /// Parameter for Objective-C 'self' argument + ObjCSelf, + + /// Parameter for Objective-C '_cmd' argument + ObjCCmd, + + /// Parameter for C++ 'this' argument + CXXThis, + + /// Parameter for C++ virtual table pointers + CXXVTT, + + /// Parameter for captured context + CapturedContext, + + /// Other implicit parameter + Other, + }; + + /// Create implicit parameter. + static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, ImplicitParamKind ParamKind); + static ImplicitParamDecl *Create(ASTContext &C, QualType T, + ImplicitParamKind ParamKind); + + static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, + IdentifierInfo *Id, QualType Type, + ImplicitParamKind ParamKind) + : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, + /*TInfo=*/nullptr, SC_None) { + NonParmVarDeclBits.ImplicitParamKind = ParamKind; + setImplicit(); + } + + ImplicitParamDecl(ASTContext &C, QualType Type, ImplicitParamKind ParamKind) + : VarDecl(ImplicitParam, C, /*DC=*/nullptr, SourceLocation(), + SourceLocation(), /*Id=*/nullptr, Type, + /*TInfo=*/nullptr, SC_None) { + NonParmVarDeclBits.ImplicitParamKind = ParamKind; + setImplicit(); + } + + /// Returns the implicit parameter kind. + ImplicitParamKind getParameterKind() const { + return static_cast<ImplicitParamKind>(NonParmVarDeclBits.ImplicitParamKind); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ImplicitParam; } +}; + +/// Represents a parameter to a function. +class ParmVarDecl : public VarDecl { +public: + enum { MaxFunctionScopeDepth = 255 }; + enum { MaxFunctionScopeIndex = 255 }; + +protected: + ParmVarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) + : VarDecl(DK, C, DC, StartLoc, IdLoc, Id, T, TInfo, S) { + assert(ParmVarDeclBits.HasInheritedDefaultArg == false); + assert(ParmVarDeclBits.DefaultArgKind == DAK_None); + assert(ParmVarDeclBits.IsKNRPromoted == false); + assert(ParmVarDeclBits.IsObjCMethodParam == false); + setDefaultArg(DefArg); + } + +public: + static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, Expr *DefArg); + + static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + void setObjCMethodScopeInfo(unsigned parameterIndex) { + ParmVarDeclBits.IsObjCMethodParam = true; + setParameterIndex(parameterIndex); + } + + void setScopeInfo(unsigned scopeDepth, unsigned parameterIndex) { + assert(!ParmVarDeclBits.IsObjCMethodParam); + + ParmVarDeclBits.ScopeDepthOrObjCQuals = scopeDepth; + assert(ParmVarDeclBits.ScopeDepthOrObjCQuals == scopeDepth + && "truncation!"); + + setParameterIndex(parameterIndex); + } + + bool isObjCMethodParameter() const { + return ParmVarDeclBits.IsObjCMethodParam; + } + + unsigned getFunctionScopeDepth() const { + if (ParmVarDeclBits.IsObjCMethodParam) return 0; + return ParmVarDeclBits.ScopeDepthOrObjCQuals; + } + + /// Returns the index of this parameter in its prototype or method scope. + unsigned getFunctionScopeIndex() const { + return getParameterIndex(); + } + + ObjCDeclQualifier getObjCDeclQualifier() const { + if (!ParmVarDeclBits.IsObjCMethodParam) return OBJC_TQ_None; + return ObjCDeclQualifier(ParmVarDeclBits.ScopeDepthOrObjCQuals); + } + void setObjCDeclQualifier(ObjCDeclQualifier QTVal) { + assert(ParmVarDeclBits.IsObjCMethodParam); + ParmVarDeclBits.ScopeDepthOrObjCQuals = QTVal; + } + + /// True if the value passed to this parameter must undergo + /// K&R-style default argument promotion: + /// + /// C99 6.5.2.2. + /// If the expression that denotes the called function has a type + /// that does not include a prototype, the integer promotions are + /// performed on each argument, and arguments that have type float + /// are promoted to double. + bool isKNRPromoted() const { + return ParmVarDeclBits.IsKNRPromoted; + } + void setKNRPromoted(bool promoted) { + ParmVarDeclBits.IsKNRPromoted = promoted; + } + + Expr *getDefaultArg(); + const Expr *getDefaultArg() const { + return const_cast<ParmVarDecl *>(this)->getDefaultArg(); + } + + void setDefaultArg(Expr *defarg); + + /// Retrieve the source range that covers the entire default + /// argument. + SourceRange getDefaultArgRange() const; + void setUninstantiatedDefaultArg(Expr *arg); + Expr *getUninstantiatedDefaultArg(); + const Expr *getUninstantiatedDefaultArg() const { + return const_cast<ParmVarDecl *>(this)->getUninstantiatedDefaultArg(); + } + + /// Determines whether this parameter has a default argument, + /// either parsed or not. + bool hasDefaultArg() const; + + /// Determines whether this parameter has a default argument that has not + /// yet been parsed. This will occur during the processing of a C++ class + /// whose member functions have default arguments, e.g., + /// @code + /// class X { + /// public: + /// void f(int x = 17); // x has an unparsed default argument now + /// }; // x has a regular default argument now + /// @endcode + bool hasUnparsedDefaultArg() const { + return ParmVarDeclBits.DefaultArgKind == DAK_Unparsed; + } + + bool hasUninstantiatedDefaultArg() const { + return ParmVarDeclBits.DefaultArgKind == DAK_Uninstantiated; + } + + /// Specify that this parameter has an unparsed default argument. + /// The argument will be replaced with a real default argument via + /// setDefaultArg when the class definition enclosing the function + /// declaration that owns this default argument is completed. + void setUnparsedDefaultArg() { + ParmVarDeclBits.DefaultArgKind = DAK_Unparsed; + } + + bool hasInheritedDefaultArg() const { + return ParmVarDeclBits.HasInheritedDefaultArg; + } + + void setHasInheritedDefaultArg(bool I = true) { + ParmVarDeclBits.HasInheritedDefaultArg = I; + } + + QualType getOriginalType() const; + + /// Determine whether this parameter is actually a function + /// parameter pack. + bool isParameterPack() const; + + /// Sets the function declaration that owns this + /// ParmVarDecl. Since ParmVarDecls are often created before the + /// FunctionDecls that own them, this routine is required to update + /// the DeclContext appropriately. + void setOwningFunction(DeclContext *FD) { setDeclContext(FD); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ParmVar; } + +private: + enum { ParameterIndexSentinel = (1 << NumParameterIndexBits) - 1 }; + + void setParameterIndex(unsigned parameterIndex) { + if (parameterIndex >= ParameterIndexSentinel) { + setParameterIndexLarge(parameterIndex); + return; + } + + ParmVarDeclBits.ParameterIndex = parameterIndex; + assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!"); + } + unsigned getParameterIndex() const { + unsigned d = ParmVarDeclBits.ParameterIndex; + return d == ParameterIndexSentinel ? getParameterIndexLarge() : d; + } + + void setParameterIndexLarge(unsigned parameterIndex); + unsigned getParameterIndexLarge() const; +}; + +enum class MultiVersionKind { + None, + Target, + CPUSpecific, + CPUDispatch +}; + +/// Represents a function declaration or definition. +/// +/// Since a given function can be declared several times in a program, +/// there may be several FunctionDecls that correspond to that +/// function. Only one of those FunctionDecls will be found when +/// traversing the list of declarations in the context of the +/// FunctionDecl (e.g., the translation unit); this FunctionDecl +/// contains all of the information known about the function. Other, +/// previous declarations of the function are available via the +/// getPreviousDecl() chain. +class FunctionDecl : public DeclaratorDecl, + public DeclContext, + public Redeclarable<FunctionDecl> { + // This class stores some data in DeclContext::FunctionDeclBits + // to save some space. Use the provided accessors to access it. +public: + /// The kind of templated function a FunctionDecl can be. + enum TemplatedKind { + TK_NonTemplate, + TK_FunctionTemplate, + TK_MemberSpecialization, + TK_FunctionTemplateSpecialization, + TK_DependentFunctionTemplateSpecialization + }; + +private: + /// A new[]'d array of pointers to VarDecls for the formal + /// parameters of this function. This is null if a prototype or if there are + /// no formals. + ParmVarDecl **ParamInfo = nullptr; + + LazyDeclStmtPtr Body; + + unsigned ODRHash; + + /// End part of this FunctionDecl's source range. + /// + /// We could compute the full range in getSourceRange(). However, when we're + /// dealing with a function definition deserialized from a PCH/AST file, + /// we can only compute the full range once the function body has been + /// de-serialized, so it's far better to have the (sometimes-redundant) + /// EndRangeLoc. + SourceLocation EndRangeLoc; + + /// The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be NULL. For function + /// declarations that describe a function template, this will be a + /// pointer to a FunctionTemplateDecl. For member functions + /// of class template specializations, this will be a MemberSpecializationInfo + /// pointer containing information about the specialization. + /// For function template specializations, this will be a + /// FunctionTemplateSpecializationInfo, which contains information about + /// the template being specialized and the template arguments involved in + /// that specialization. + llvm::PointerUnion4<FunctionTemplateDecl *, + MemberSpecializationInfo *, + FunctionTemplateSpecializationInfo *, + DependentFunctionTemplateSpecializationInfo *> + TemplateOrSpecialization; + + /// Provides source/type location info for the declaration name embedded in + /// the DeclaratorDecl base class. + DeclarationNameLoc DNLoc; + + /// Specify that this function declaration is actually a function + /// template specialization. + /// + /// \param C the ASTContext. + /// + /// \param Template the function template that this function template + /// specialization specializes. + /// + /// \param TemplateArgs the template arguments that produced this + /// function template specialization from the template. + /// + /// \param InsertPos If non-NULL, the position in the function template + /// specialization set where the function template specialization data will + /// be inserted. + /// + /// \param TSK the kind of template specialization this is. + /// + /// \param TemplateArgsAsWritten location info of template arguments. + /// + /// \param PointOfInstantiation point at which the function template + /// specialization was first instantiated. + void setFunctionTemplateSpecialization(ASTContext &C, + FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs, + void *InsertPos, + TemplateSpecializationKind TSK, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation PointOfInstantiation); + + /// Specify that this record is an instantiation of the + /// member function FD. + void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD, + TemplateSpecializationKind TSK); + + void setParams(ASTContext &C, ArrayRef<ParmVarDecl *> NewParamInfo); + + // This is unfortunately needed because ASTDeclWriter::VisitFunctionDecl + // need to access this bit but we want to avoid making ASTDeclWriter + // a friend of FunctionDeclBitfields just for this. + bool isDeletedBit() const { return FunctionDeclBits.IsDeleted; } + + /// Whether an ODRHash has been stored. + bool hasODRHash() const { return FunctionDeclBits.HasODRHash; } + + /// State that an ODRHash has been stored. + void setHasODRHash(bool B = true) { FunctionDeclBits.HasODRHash = B; } + +protected: + FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified, + bool isConstexprSpecified); + + using redeclarable_base = Redeclarable<FunctionDecl>; + + FunctionDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + + FunctionDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + + FunctionDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + static FunctionDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation NLoc, + DeclarationName N, QualType T, + TypeSourceInfo *TInfo, + StorageClass SC, + bool isInlineSpecified = false, + bool hasWrittenPrototype = true, + bool isConstexprSpecified = false) { + DeclarationNameInfo NameInfo(N, NLoc); + return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, + SC, + isInlineSpecified, hasWrittenPrototype, + isConstexprSpecified); + } + + static FunctionDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass SC, + bool isInlineSpecified, + bool hasWrittenPrototype, + bool isConstexprSpecified = false); + + static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); + } + + void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, + bool Qualified) const override; + + void setRangeEnd(SourceLocation E) { EndRangeLoc = E; } + + SourceRange getSourceRange() const override LLVM_READONLY; + + // Function definitions. + // + // A function declaration may be: + // - a non defining declaration, + // - a definition. A function may be defined because: + // - it has a body, or will have it in the case of late parsing. + // - it has an uninstantiated body. The body does not exist because the + // function is not used yet, but the declaration is considered a + // definition and does not allow other definition of this function. + // - it does not have a user specified body, but it does not allow + // redefinition, because it is deleted/defaulted or is defined through + // some other mechanism (alias, ifunc). + + /// Returns true if the function has a body. + /// + /// The function body might be in any of the (re-)declarations of this + /// function. The variant that accepts a FunctionDecl pointer will set that + /// function declaration to the actual declaration containing the body (if + /// there is one). + bool hasBody(const FunctionDecl *&Definition) const; + + bool hasBody() const override { + const FunctionDecl* Definition; + return hasBody(Definition); + } + + /// Returns whether the function has a trivial body that does not require any + /// specific codegen. + bool hasTrivialBody() const; + + /// Returns true if the function has a definition that does not need to be + /// instantiated. + /// + /// The variant that accepts a FunctionDecl pointer will set that function + /// declaration to the declaration that is a definition (if there is one). + bool isDefined(const FunctionDecl *&Definition) const; + + virtual bool isDefined() const { + const FunctionDecl* Definition; + return isDefined(Definition); + } + + /// Get the definition for this declaration. + FunctionDecl *getDefinition() { + const FunctionDecl *Definition; + if (isDefined(Definition)) + return const_cast<FunctionDecl *>(Definition); + return nullptr; + } + const FunctionDecl *getDefinition() const { + return const_cast<FunctionDecl *>(this)->getDefinition(); + } + + /// Retrieve the body (definition) of the function. The function body might be + /// in any of the (re-)declarations of this function. The variant that accepts + /// a FunctionDecl pointer will set that function declaration to the actual + /// declaration containing the body (if there is one). + /// NOTE: For checking if there is a body, use hasBody() instead, to avoid + /// unnecessary AST de-serialization of the body. + Stmt *getBody(const FunctionDecl *&Definition) const; + + Stmt *getBody() const override { + const FunctionDecl* Definition; + return getBody(Definition); + } + + /// Returns whether this specific declaration of the function is also a + /// definition that does not contain uninstantiated body. + /// + /// This does not determine whether the function has been defined (e.g., in a + /// previous definition); for that information, use isDefined. + bool isThisDeclarationADefinition() const { + return isDeletedAsWritten() || isDefaulted() || Body || hasSkippedBody() || + isLateTemplateParsed() || willHaveBody() || hasDefiningAttr(); + } + + /// Returns whether this specific declaration of the function has a body. + bool doesThisDeclarationHaveABody() const { + return Body || isLateTemplateParsed(); + } + + void setBody(Stmt *B); + void setLazyBody(uint64_t Offset) { Body = Offset; } + + /// Whether this function is variadic. + bool isVariadic() const; + + /// Whether this function is marked as virtual explicitly. + bool isVirtualAsWritten() const { + return FunctionDeclBits.IsVirtualAsWritten; + } + + /// State that this function is marked as virtual explicitly. + void setVirtualAsWritten(bool V) { FunctionDeclBits.IsVirtualAsWritten = V; } + + /// Whether this virtual function is pure, i.e. makes the containing class + /// abstract. + bool isPure() const { return FunctionDeclBits.IsPure; } + void setPure(bool P = true); + + /// Whether this templated function will be late parsed. + bool isLateTemplateParsed() const { + return FunctionDeclBits.IsLateTemplateParsed; + } + + /// State that this templated function will be late parsed. + void setLateTemplateParsed(bool ILT = true) { + FunctionDeclBits.IsLateTemplateParsed = ILT; + } + + /// Whether this function is "trivial" in some specialized C++ senses. + /// Can only be true for default constructors, copy constructors, + /// copy assignment operators, and destructors. Not meaningful until + /// the class has been fully built by Sema. + bool isTrivial() const { return FunctionDeclBits.IsTrivial; } + void setTrivial(bool IT) { FunctionDeclBits.IsTrivial = IT; } + + bool isTrivialForCall() const { return FunctionDeclBits.IsTrivialForCall; } + void setTrivialForCall(bool IT) { FunctionDeclBits.IsTrivialForCall = IT; } + + /// Whether this function is defaulted per C++0x. Only valid for + /// special member functions. + bool isDefaulted() const { return FunctionDeclBits.IsDefaulted; } + void setDefaulted(bool D = true) { FunctionDeclBits.IsDefaulted = D; } + + /// Whether this function is explicitly defaulted per C++0x. Only valid + /// for special member functions. + bool isExplicitlyDefaulted() const { + return FunctionDeclBits.IsExplicitlyDefaulted; + } + + /// State that this function is explicitly defaulted per C++0x. Only valid + /// for special member functions. + void setExplicitlyDefaulted(bool ED = true) { + FunctionDeclBits.IsExplicitlyDefaulted = ED; + } + + /// Whether falling off this function implicitly returns null/zero. + /// If a more specific implicit return value is required, front-ends + /// should synthesize the appropriate return statements. + bool hasImplicitReturnZero() const { + return FunctionDeclBits.HasImplicitReturnZero; + } + + /// State that falling off this function implicitly returns null/zero. + /// If a more specific implicit return value is required, front-ends + /// should synthesize the appropriate return statements. + void setHasImplicitReturnZero(bool IRZ) { + FunctionDeclBits.HasImplicitReturnZero = IRZ; + } + + /// Whether this function has a prototype, either because one + /// was explicitly written or because it was "inherited" by merging + /// a declaration without a prototype with a declaration that has a + /// prototype. + bool hasPrototype() const { + return hasWrittenPrototype() || hasInheritedPrototype(); + } + + /// Whether this function has a written prototype. + bool hasWrittenPrototype() const { + return FunctionDeclBits.HasWrittenPrototype; + } + + /// State that this function has a written prototype. + void setHasWrittenPrototype(bool P = true) { + FunctionDeclBits.HasWrittenPrototype = P; + } + + /// Whether this function inherited its prototype from a + /// previous declaration. + bool hasInheritedPrototype() const { + return FunctionDeclBits.HasInheritedPrototype; + } + + /// State that this function inherited its prototype from a + /// previous declaration. + void setHasInheritedPrototype(bool P = true) { + FunctionDeclBits.HasInheritedPrototype = P; + } + + /// Whether this is a (C++11) constexpr function or constexpr constructor. + bool isConstexpr() const { return FunctionDeclBits.IsConstexpr; } + void setConstexpr(bool IC) { FunctionDeclBits.IsConstexpr = IC; } + + /// Whether the instantiation of this function is pending. + /// This bit is set when the decision to instantiate this function is made + /// and unset if and when the function body is created. That leaves out + /// cases where instantiation did not happen because the template definition + /// was not seen in this TU. This bit remains set in those cases, under the + /// assumption that the instantiation will happen in some other TU. + bool instantiationIsPending() const { + return FunctionDeclBits.InstantiationIsPending; + } + + /// State that the instantiation of this function is pending. + /// (see instantiationIsPending) + void setInstantiationIsPending(bool IC) { + FunctionDeclBits.InstantiationIsPending = IC; + } + + /// Indicates the function uses __try. + bool usesSEHTry() const { return FunctionDeclBits.UsesSEHTry; } + void setUsesSEHTry(bool UST) { FunctionDeclBits.UsesSEHTry = UST; } + + /// Whether this function has been deleted. + /// + /// A function that is "deleted" (via the C++0x "= delete" syntax) + /// acts like a normal function, except that it cannot actually be + /// called or have its address taken. Deleted functions are + /// typically used in C++ overload resolution to attract arguments + /// whose type or lvalue/rvalue-ness would permit the use of a + /// different overload that would behave incorrectly. For example, + /// one might use deleted functions to ban implicit conversion from + /// a floating-point number to an Integer type: + /// + /// @code + /// struct Integer { + /// Integer(long); // construct from a long + /// Integer(double) = delete; // no construction from float or double + /// Integer(long double) = delete; // no construction from long double + /// }; + /// @endcode + // If a function is deleted, its first declaration must be. + bool isDeleted() const { + return getCanonicalDecl()->FunctionDeclBits.IsDeleted; + } + + bool isDeletedAsWritten() const { + return FunctionDeclBits.IsDeleted && !isDefaulted(); + } + + void setDeletedAsWritten(bool D = true) { FunctionDeclBits.IsDeleted = D; } + + /// Determines whether this function is "main", which is the + /// entry point into an executable program. + bool isMain() const; + + /// Determines whether this function is a MSVCRT user defined entry + /// point. + bool isMSVCRTEntryPoint() const; + + /// Determines whether this operator new or delete is one + /// of the reserved global placement operators: + /// void *operator new(size_t, void *); + /// void *operator new[](size_t, void *); + /// void operator delete(void *, void *); + /// void operator delete[](void *, void *); + /// These functions have special behavior under [new.delete.placement]: + /// These functions are reserved, a C++ program may not define + /// functions that displace the versions in the Standard C++ library. + /// The provisions of [basic.stc.dynamic] do not apply to these + /// reserved placement forms of operator new and operator delete. + /// + /// This function must be an allocation or deallocation function. + bool isReservedGlobalPlacementOperator() const; + + /// Determines whether this function is one of the replaceable + /// global allocation functions: + /// void *operator new(size_t); + /// void *operator new(size_t, const std::nothrow_t &) noexcept; + /// void *operator new[](size_t); + /// void *operator new[](size_t, const std::nothrow_t &) noexcept; + /// void operator delete(void *) noexcept; + /// void operator delete(void *, std::size_t) noexcept; [C++1y] + /// void operator delete(void *, const std::nothrow_t &) noexcept; + /// void operator delete[](void *) noexcept; + /// void operator delete[](void *, std::size_t) noexcept; [C++1y] + /// void operator delete[](void *, const std::nothrow_t &) noexcept; + /// These functions have special behavior under C++1y [expr.new]: + /// An implementation is allowed to omit a call to a replaceable global + /// allocation function. [...] + /// + /// If this function is an aligned allocation/deallocation function, return + /// true through IsAligned. + bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const; + + /// Determine whether this is a destroying operator delete. + bool isDestroyingOperatorDelete() const; + + /// Compute the language linkage. + LanguageLinkage getLanguageLinkage() const; + + /// Determines whether this function is a function with + /// external, C linkage. + bool isExternC() const; + + /// Determines whether this function's context is, or is nested within, + /// a C++ extern "C" linkage spec. + bool isInExternCContext() const; + + /// Determines whether this function's context is, or is nested within, + /// a C++ extern "C++" linkage spec. + bool isInExternCXXContext() const; + + /// Determines whether this is a global function. + bool isGlobal() const; + + /// Determines whether this function is known to be 'noreturn', through + /// an attribute on its declaration or its type. + bool isNoReturn() const; + + /// True if the function was a definition but its body was skipped. + bool hasSkippedBody() const { return FunctionDeclBits.HasSkippedBody; } + void setHasSkippedBody(bool Skipped = true) { + FunctionDeclBits.HasSkippedBody = Skipped; + } + + /// True if this function will eventually have a body, once it's fully parsed. + bool willHaveBody() const { return FunctionDeclBits.WillHaveBody; } + void setWillHaveBody(bool V = true) { FunctionDeclBits.WillHaveBody = V; } + + /// True if this function is considered a multiversioned function. + bool isMultiVersion() const { + return getCanonicalDecl()->FunctionDeclBits.IsMultiVersion; + } + + /// Sets the multiversion state for this declaration and all of its + /// redeclarations. + void setIsMultiVersion(bool V = true) { + getCanonicalDecl()->FunctionDeclBits.IsMultiVersion = V; + } + + /// Gets the kind of multiversioning attribute this declaration has. Note that + /// this can return a value even if the function is not multiversion, such as + /// the case of 'target'. + MultiVersionKind getMultiVersionKind() const; + + + /// True if this function is a multiversioned dispatch function as a part of + /// the cpu_specific/cpu_dispatch functionality. + bool isCPUDispatchMultiVersion() const; + /// True if this function is a multiversioned processor specific function as a + /// part of the cpu_specific/cpu_dispatch functionality. + bool isCPUSpecificMultiVersion() const; + + /// True if this function is a multiversioned dispatch function as a part of + /// the target functionality. + bool isTargetMultiVersion() const; + + void setPreviousDeclaration(FunctionDecl * PrevDecl); + + FunctionDecl *getCanonicalDecl() override; + const FunctionDecl *getCanonicalDecl() const { + return const_cast<FunctionDecl*>(this)->getCanonicalDecl(); + } + + unsigned getBuiltinID() const; + + // ArrayRef interface to parameters. + ArrayRef<ParmVarDecl *> parameters() const { + return {ParamInfo, getNumParams()}; + } + MutableArrayRef<ParmVarDecl *> parameters() { + return {ParamInfo, getNumParams()}; + } + + // Iterator access to formal parameters. + using param_iterator = MutableArrayRef<ParmVarDecl *>::iterator; + using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator; + + bool param_empty() const { return parameters().empty(); } + param_iterator param_begin() { return parameters().begin(); } + param_iterator param_end() { return parameters().end(); } + param_const_iterator param_begin() const { return parameters().begin(); } + param_const_iterator param_end() const { return parameters().end(); } + size_t param_size() const { return parameters().size(); } + + /// Return the number of parameters this function must have based on its + /// FunctionType. This is the length of the ParamInfo array after it has been + /// created. + unsigned getNumParams() const; + + const ParmVarDecl *getParamDecl(unsigned i) const { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + void setParams(ArrayRef<ParmVarDecl *> NewParamInfo) { + setParams(getASTContext(), NewParamInfo); + } + + /// Returns the minimum number of arguments needed to call this function. This + /// may be fewer than the number of function parameters, if some of the + /// parameters have default arguments (in C++). + unsigned getMinRequiredArguments() const; + + QualType getReturnType() const { + return getType()->castAs<FunctionType>()->getReturnType(); + } + + /// Attempt to compute an informative source range covering the + /// function return type. This may omit qualifiers and other information with + /// limited representation in the AST. + SourceRange getReturnTypeSourceRange() const; + + /// Get the declared return type, which may differ from the actual return + /// type if the return type is deduced. + QualType getDeclaredReturnType() const { + auto *TSI = getTypeSourceInfo(); + QualType T = TSI ? TSI->getType() : getType(); + return T->castAs<FunctionType>()->getReturnType(); + } + + /// Attempt to compute an informative source range covering the + /// function exception specification, if any. + SourceRange getExceptionSpecSourceRange() const; + + /// Determine the type of an expression that calls this function. + QualType getCallResultType() const { + return getType()->castAs<FunctionType>()->getCallResultType( + getASTContext()); + } + + /// Returns the storage class as written in the source. For the + /// computed linkage of symbol, see getLinkage. + StorageClass getStorageClass() const { + return static_cast<StorageClass>(FunctionDeclBits.SClass); + } + + /// Sets the storage class as written in the source. + void setStorageClass(StorageClass SClass) { + FunctionDeclBits.SClass = SClass; + } + + /// Determine whether the "inline" keyword was specified for this + /// function. + bool isInlineSpecified() const { return FunctionDeclBits.IsInlineSpecified; } + + /// Set whether the "inline" keyword was specified for this function. + void setInlineSpecified(bool I) { + FunctionDeclBits.IsInlineSpecified = I; + FunctionDeclBits.IsInline = I; + } + + /// Flag that this function is implicitly inline. + void setImplicitlyInline(bool I = true) { FunctionDeclBits.IsInline = I; } + + /// Determine whether this function should be inlined, because it is + /// either marked "inline" or "constexpr" or is a member function of a class + /// that was defined in the class body. + bool isInlined() const { return FunctionDeclBits.IsInline; } + + /// Whether this function is marked as explicit explicitly. + bool isExplicitSpecified() const { + return FunctionDeclBits.IsExplicitSpecified; + } + + /// State that this function is marked as explicit explicitly. + void setExplicitSpecified(bool ExpSpec = true) { + FunctionDeclBits.IsExplicitSpecified = ExpSpec; + } + + bool isInlineDefinitionExternallyVisible() const; + + bool isMSExternInline() const; + + bool doesDeclarationForceExternallyVisibleDefinition() const; + + /// Whether this function declaration represents an C++ overloaded + /// operator, e.g., "operator+". + bool isOverloadedOperator() const { + return getOverloadedOperator() != OO_None; + } + + OverloadedOperatorKind getOverloadedOperator() const; + + const IdentifierInfo *getLiteralIdentifier() const; + + /// If this function is an instantiation of a member function + /// of a class template specialization, retrieves the function from + /// which it was instantiated. + /// + /// This routine will return non-NULL for (non-templated) member + /// functions of class templates and for instantiations of function + /// templates. For example, given: + /// + /// \code + /// template<typename T> + /// struct X { + /// void f(T); + /// }; + /// \endcode + /// + /// The declaration for X<int>::f is a (non-templated) FunctionDecl + /// whose parent is the class template specialization X<int>. For + /// this declaration, getInstantiatedFromFunction() will return + /// the FunctionDecl X<T>::A. When a complete definition of + /// X<int>::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberFunction(). + FunctionDecl *getInstantiatedFromMemberFunction() const; + + /// What kind of templated function this is. + TemplatedKind getTemplatedKind() const; + + /// If this function is an instantiation of a member function of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// Specify that this record is an instantiation of the + /// member function FD. + void setInstantiationOfMemberFunction(FunctionDecl *FD, + TemplateSpecializationKind TSK) { + setInstantiationOfMemberFunction(getASTContext(), FD, TSK); + } + + /// Retrieves the function template that is described by this + /// function declaration. + /// + /// Every function template is represented as a FunctionTemplateDecl + /// and a FunctionDecl (or something derived from FunctionDecl). The + /// former contains template properties (such as the template + /// parameter lists) while the latter contains the actual + /// description of the template's + /// contents. FunctionTemplateDecl::getTemplatedDecl() retrieves the + /// FunctionDecl that describes the function template, + /// getDescribedFunctionTemplate() retrieves the + /// FunctionTemplateDecl from a FunctionDecl. + FunctionTemplateDecl *getDescribedFunctionTemplate() const; + + void setDescribedFunctionTemplate(FunctionTemplateDecl *Template); + + /// Determine whether this function is a function template + /// specialization. + bool isFunctionTemplateSpecialization() const { + return getPrimaryTemplate() != nullptr; + } + + /// Retrieve the class scope template pattern that this function + /// template specialization is instantiated from. + FunctionDecl *getClassScopeSpecializationPattern() const; + + /// If this function is actually a function template specialization, + /// retrieve information about this function template specialization. + /// Otherwise, returns NULL. + FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const; + + /// Determines whether this function is a function template + /// specialization or a member of a class template specialization that can + /// be implicitly instantiated. + bool isImplicitlyInstantiable() const; + + /// Determines if the given function was instantiated from a + /// function template. + bool isTemplateInstantiation() const; + + /// Retrieve the function declaration from which this function could + /// be instantiated, if it is an instantiation (rather than a non-template + /// or a specialization, for example). + FunctionDecl *getTemplateInstantiationPattern() const; + + /// Retrieve the primary template that this function template + /// specialization either specializes or was instantiated from. + /// + /// If this function declaration is not a function template specialization, + /// returns NULL. + FunctionTemplateDecl *getPrimaryTemplate() const; + + /// Retrieve the template arguments used to produce this function + /// template specialization from the primary template. + /// + /// If this function declaration is not a function template specialization, + /// returns NULL. + const TemplateArgumentList *getTemplateSpecializationArgs() const; + + /// Retrieve the template argument list as written in the sources, + /// if any. + /// + /// If this function declaration is not a function template specialization + /// or if it had no explicit template argument list, returns NULL. + /// Note that it an explicit template argument list may be written empty, + /// e.g., template<> void foo<>(char* s); + const ASTTemplateArgumentListInfo* + getTemplateSpecializationArgsAsWritten() const; + + /// Specify that this function declaration is actually a function + /// template specialization. + /// + /// \param Template the function template that this function template + /// specialization specializes. + /// + /// \param TemplateArgs the template arguments that produced this + /// function template specialization from the template. + /// + /// \param InsertPos If non-NULL, the position in the function template + /// specialization set where the function template specialization data will + /// be inserted. + /// + /// \param TSK the kind of template specialization this is. + /// + /// \param TemplateArgsAsWritten location info of template arguments. + /// + /// \param PointOfInstantiation point at which the function template + /// specialization was first instantiated. + void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs, + void *InsertPos, + TemplateSpecializationKind TSK = TSK_ImplicitInstantiation, + const TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr, + SourceLocation PointOfInstantiation = SourceLocation()) { + setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs, + InsertPos, TSK, TemplateArgsAsWritten, + PointOfInstantiation); + } + + /// Specifies that this function declaration is actually a + /// dependent function template specialization. + void setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs); + + DependentFunctionTemplateSpecializationInfo * + getDependentSpecializationInfo() const; + + /// Determine what kind of template instantiation this function + /// represents. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// Determine what kind of template instantiation this function + /// represents. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// Retrieve the (first) point of instantiation of a function template + /// specialization or a member of a class template specialization. + /// + /// \returns the first point of instantiation, if this function was + /// instantiated from a template; otherwise, returns an invalid source + /// location. + SourceLocation getPointOfInstantiation() const; + + /// Determine whether this is or was instantiated from an out-of-line + /// definition of a member function. + bool isOutOfLine() const override; + + /// Identify a memory copying or setting function. + /// If the given function is a memory copy or setting function, returns + /// the corresponding Builtin ID. If the function is not a memory function, + /// returns 0. + unsigned getMemoryFunctionKind() const; + + /// Returns ODRHash of the function. This value is calculated and + /// stored on first call, then the stored value returned on the other calls. + unsigned getODRHash(); + + /// Returns cached ODRHash of the function. This must have been previously + /// computed and stored. + unsigned getODRHash() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstFunction && K <= lastFunction; + } + static DeclContext *castToDeclContext(const FunctionDecl *D) { + return static_cast<DeclContext *>(const_cast<FunctionDecl*>(D)); + } + static FunctionDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<FunctionDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// Represents a member of a struct/union/class. +class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { + unsigned BitField : 1; + unsigned Mutable : 1; + mutable unsigned CachedFieldIndex : 30; + + /// The kinds of value we can store in InitializerOrBitWidth. + /// + /// Note that this is compatible with InClassInitStyle except for + /// ISK_CapturedVLAType. + enum InitStorageKind { + /// If the pointer is null, there's nothing special. Otherwise, + /// this is a bitfield and the pointer is the Expr* storing the + /// bit-width. + ISK_NoInit = (unsigned) ICIS_NoInit, + + /// The pointer is an (optional due to delayed parsing) Expr* + /// holding the copy-initializer. + ISK_InClassCopyInit = (unsigned) ICIS_CopyInit, + + /// The pointer is an (optional due to delayed parsing) Expr* + /// holding the list-initializer. + ISK_InClassListInit = (unsigned) ICIS_ListInit, + + /// The pointer is a VariableArrayType* that's been captured; + /// the enclosing context is a lambda or captured statement. + ISK_CapturedVLAType, + }; + + /// If this is a bitfield with a default member initializer, this + /// structure is used to represent the two expressions. + struct InitAndBitWidth { + Expr *Init; + Expr *BitWidth; + }; + + /// Storage for either the bit-width, the in-class initializer, or + /// both (via InitAndBitWidth), or the captured variable length array bound. + /// + /// If the storage kind is ISK_InClassCopyInit or + /// ISK_InClassListInit, but the initializer is null, then this + /// field has an in-class initializer that has not yet been parsed + /// and attached. + // FIXME: Tail-allocate this to reduce the size of FieldDecl in the + // overwhelmingly common case that we have none of these things. + llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage; + +protected: + FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + InClassInitStyle InitStyle) + : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), + BitField(false), Mutable(Mutable), CachedFieldIndex(0), + InitStorage(nullptr, (InitStorageKind) InitStyle) { + if (BW) + setBitWidth(BW); + } + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + + static FieldDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + InClassInitStyle InitStyle); + + static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// Returns the index of this field within its record, + /// as appropriate for passing to ASTRecordLayout::getFieldOffset. + unsigned getFieldIndex() const; + + /// Determines whether this field is mutable (C++ only). + bool isMutable() const { return Mutable; } + + /// Determines whether this field is a bitfield. + bool isBitField() const { return BitField; } + + /// Determines whether this is an unnamed bitfield. + bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); } + + /// Determines whether this field is a + /// representative for an anonymous struct or union. Such fields are + /// unnamed and are implicitly generated by the implementation to + /// store the data for the anonymous union or struct. + bool isAnonymousStructOrUnion() const; + + Expr *getBitWidth() const { + if (!BitField) + return nullptr; + void *Ptr = InitStorage.getPointer(); + if (getInClassInitStyle()) + return static_cast<InitAndBitWidth*>(Ptr)->BitWidth; + return static_cast<Expr*>(Ptr); + } + + unsigned getBitWidthValue(const ASTContext &Ctx) const; + + /// Set the bit-field width for this member. + // Note: used by some clients (i.e., do not remove it). + void setBitWidth(Expr *Width) { + assert(!hasCapturedVLAType() && !BitField && + "bit width or captured type already set"); + assert(Width && "no bit width specified"); + InitStorage.setPointer( + InitStorage.getInt() + ? new (getASTContext()) + InitAndBitWidth{getInClassInitializer(), Width} + : static_cast<void*>(Width)); + BitField = true; + } + + /// Remove the bit-field width from this member. + // Note: used by some clients (i.e., do not remove it). + void removeBitWidth() { + assert(isBitField() && "no bitfield width to remove"); + InitStorage.setPointer(getInClassInitializer()); + BitField = false; + } + + /// Is this a zero-length bit-field? Such bit-fields aren't really bit-fields + /// at all and instead act as a separator between contiguous runs of other + /// bit-fields. + bool isZeroLengthBitField(const ASTContext &Ctx) const; + + /// Get the kind of (C++11) default member initializer that this field has. + InClassInitStyle getInClassInitStyle() const { + InitStorageKind storageKind = InitStorage.getInt(); + return (storageKind == ISK_CapturedVLAType + ? ICIS_NoInit : (InClassInitStyle) storageKind); + } + + /// Determine whether this member has a C++11 default member initializer. + bool hasInClassInitializer() const { + return getInClassInitStyle() != ICIS_NoInit; + } + + /// Get the C++11 default member initializer for this member, or null if one + /// has not been set. If a valid declaration has a default member initializer, + /// but this returns null, then we have not parsed and attached it yet. + Expr *getInClassInitializer() const { + if (!hasInClassInitializer()) + return nullptr; + void *Ptr = InitStorage.getPointer(); + if (BitField) + return static_cast<InitAndBitWidth*>(Ptr)->Init; + return static_cast<Expr*>(Ptr); + } + + /// Set the C++11 in-class initializer for this member. + void setInClassInitializer(Expr *Init) { + assert(hasInClassInitializer() && !getInClassInitializer()); + if (BitField) + static_cast<InitAndBitWidth*>(InitStorage.getPointer())->Init = Init; + else + InitStorage.setPointer(Init); + } + + /// Remove the C++11 in-class initializer from this member. + void removeInClassInitializer() { + assert(hasInClassInitializer() && "no initializer to remove"); + InitStorage.setPointerAndInt(getBitWidth(), ISK_NoInit); + } + + /// Determine whether this member captures the variable length array + /// type. + bool hasCapturedVLAType() const { + return InitStorage.getInt() == ISK_CapturedVLAType; + } + + /// Get the captured variable length array type. + const VariableArrayType *getCapturedVLAType() const { + return hasCapturedVLAType() ? static_cast<const VariableArrayType *>( + InitStorage.getPointer()) + : nullptr; + } + + /// Set the captured variable length array type for this field. + void setCapturedVLAType(const VariableArrayType *VLAType); + + /// Returns the parent of this field declaration, which + /// is the struct in which this field is defined. + const RecordDecl *getParent() const { + return cast<RecordDecl>(getDeclContext()); + } + + RecordDecl *getParent() { + return cast<RecordDecl>(getDeclContext()); + } + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Retrieves the canonical declaration of this field. + FieldDecl *getCanonicalDecl() override { return getFirstDecl(); } + const FieldDecl *getCanonicalDecl() const { return getFirstDecl(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstField && K <= lastField; } +}; + +/// An instance of this object exists for each enum constant +/// that is defined. For example, in "enum X {a,b}", each of a/b are +/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a +/// TagType for the X EnumDecl. +class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> { + Stmt *Init; // an integer constant expression + llvm::APSInt Val; // The value. + +protected: + EnumConstantDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *E, + const llvm::APSInt &V) + : ValueDecl(EnumConstant, DC, L, Id, T), Init((Stmt*)E), Val(V) {} + +public: + friend class StmtIteratorBase; + + static EnumConstantDecl *Create(ASTContext &C, EnumDecl *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, Expr *E, + const llvm::APSInt &V); + static EnumConstantDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + const Expr *getInitExpr() const { return (const Expr*) Init; } + Expr *getInitExpr() { return (Expr*) Init; } + const llvm::APSInt &getInitVal() const { return Val; } + + void setInitExpr(Expr *E) { Init = (Stmt*) E; } + void setInitVal(const llvm::APSInt &V) { Val = V; } + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Retrieves the canonical declaration of this enumerator. + EnumConstantDecl *getCanonicalDecl() override { return getFirstDecl(); } + const EnumConstantDecl *getCanonicalDecl() const { return getFirstDecl(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == EnumConstant; } +}; + +/// Represents a field injected from an anonymous union/struct into the parent +/// scope. These are always implicit. +class IndirectFieldDecl : public ValueDecl, + public Mergeable<IndirectFieldDecl> { + NamedDecl **Chaining; + unsigned ChainingSize; + + IndirectFieldDecl(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, + MutableArrayRef<NamedDecl *> CH); + + void anchor() override; + +public: + friend class ASTDeclReader; + + static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, llvm::MutableArrayRef<NamedDecl *> CH); + + static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + using chain_iterator = ArrayRef<NamedDecl *>::const_iterator; + + ArrayRef<NamedDecl *> chain() const { + return llvm::makeArrayRef(Chaining, ChainingSize); + } + chain_iterator chain_begin() const { return chain().begin(); } + chain_iterator chain_end() const { return chain().end(); } + + unsigned getChainingSize() const { return ChainingSize; } + + FieldDecl *getAnonField() const { + assert(chain().size() >= 2); + return cast<FieldDecl>(chain().back()); + } + + VarDecl *getVarDecl() const { + assert(chain().size() >= 2); + return dyn_cast<VarDecl>(chain().front()); + } + + IndirectFieldDecl *getCanonicalDecl() override { return getFirstDecl(); } + const IndirectFieldDecl *getCanonicalDecl() const { return getFirstDecl(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == IndirectField; } +}; + +/// Represents a declaration of a type. +class TypeDecl : public NamedDecl { + friend class ASTContext; + + /// This indicates the Type object that represents + /// this TypeDecl. It is a cache maintained by + /// ASTContext::getTypedefType, ASTContext::getTagDeclType, and + /// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl. + mutable const Type *TypeForDecl = nullptr; + + /// The start of the source range for this declaration. + SourceLocation LocStart; + + void anchor() override; + +protected: + TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation StartL = SourceLocation()) + : NamedDecl(DK, DC, L, Id), LocStart(StartL) {} + +public: + // Low-level accessor. If you just want the type defined by this node, + // check out ASTContext::getTypeDeclType or one of + // ASTContext::getTypedefType, ASTContext::getRecordType, etc. if you + // already know the specific kind of node this is. + const Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(const Type *TD) { TypeForDecl = TD; } + + SourceLocation getBeginLoc() const LLVM_READONLY { return LocStart; } + void setLocStart(SourceLocation L) { LocStart = L; } + SourceRange getSourceRange() const override LLVM_READONLY { + if (LocStart.isValid()) + return SourceRange(LocStart, getLocation()); + else + return SourceRange(getLocation()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstType && K <= lastType; } +}; + +/// Base class for declarations which introduce a typedef-name. +class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> { + struct alignas(8) ModedTInfo { + TypeSourceInfo *first; + QualType second; + }; + + /// If int part is 0, we have not computed IsTransparentTag. + /// Otherwise, IsTransparentTag is (getInt() >> 1). + mutable llvm::PointerIntPair< + llvm::PointerUnion<TypeSourceInfo *, ModedTInfo *>, 2> + MaybeModedTInfo; + + void anchor() override; + +protected: + TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C), + MaybeModedTInfo(TInfo, 0) {} + + using redeclarable_base = Redeclarable<TypedefNameDecl>; + + TypedefNameDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + + TypedefNameDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + + TypedefNameDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + +public: + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + bool isModed() const { + return MaybeModedTInfo.getPointer().is<ModedTInfo *>(); + } + + TypeSourceInfo *getTypeSourceInfo() const { + return isModed() ? MaybeModedTInfo.getPointer().get<ModedTInfo *>()->first + : MaybeModedTInfo.getPointer().get<TypeSourceInfo *>(); + } + + QualType getUnderlyingType() const { + return isModed() ? MaybeModedTInfo.getPointer().get<ModedTInfo *>()->second + : MaybeModedTInfo.getPointer() + .get<TypeSourceInfo *>() + ->getType(); + } + + void setTypeSourceInfo(TypeSourceInfo *newType) { + MaybeModedTInfo.setPointer(newType); + } + + void setModedTypeSourceInfo(TypeSourceInfo *unmodedTSI, QualType modedTy) { + MaybeModedTInfo.setPointer(new (getASTContext(), 8) + ModedTInfo({unmodedTSI, modedTy})); + } + + /// Retrieves the canonical declaration of this typedef-name. + TypedefNameDecl *getCanonicalDecl() override { return getFirstDecl(); } + const TypedefNameDecl *getCanonicalDecl() const { return getFirstDecl(); } + + /// Retrieves the tag declaration for which this is the typedef name for + /// linkage purposes, if any. + /// + /// \param AnyRedecl Look for the tag declaration in any redeclaration of + /// this typedef declaration. + TagDecl *getAnonDeclWithTypedefName(bool AnyRedecl = false) const; + + /// Determines if this typedef shares a name and spelling location with its + /// underlying tag type, as is the case with the NS_ENUM macro. + bool isTransparentTag() const { + if (MaybeModedTInfo.getInt()) + return MaybeModedTInfo.getInt() & 0x2; + return isTransparentTagSlow(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstTypedefName && K <= lastTypedefName; + } + +private: + bool isTransparentTagSlow() const; +}; + +/// Represents the declaration of a typedef-name via the 'typedef' +/// type specifier. +class TypedefDecl : public TypedefNameDecl { + TypedefDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypedefNameDecl(Typedef, C, DC, StartLoc, IdLoc, Id, TInfo) {} + +public: + static TypedefDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo); + static TypedefDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Typedef; } +}; + +/// Represents the declaration of a typedef-name via a C++11 +/// alias-declaration. +class TypeAliasDecl : public TypedefNameDecl { + /// The template for which this is the pattern, if any. + TypeAliasTemplateDecl *Template; + + TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo), + Template(nullptr) {} + +public: + static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo); + static TypeAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + TypeAliasTemplateDecl *getDescribedAliasTemplate() const { return Template; } + void setDescribedAliasTemplate(TypeAliasTemplateDecl *TAT) { Template = TAT; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TypeAlias; } +}; + +/// Represents the declaration of a struct/union/class/enum. +class TagDecl : public TypeDecl, + public DeclContext, + public Redeclarable<TagDecl> { + // This class stores some data in DeclContext::TagDeclBits + // to save some space. Use the provided accessors to access it. +public: + // This is really ugly. + using TagKind = TagTypeKind; + +private: + SourceRange BraceRange; + + // A struct representing syntactic qualifier info, + // to be used for the (uncommon) case of out-of-line declarations. + using ExtInfo = QualifierInfo; + + /// If the (out-of-line) tag declaration name + /// is qualified, it points to the qualifier info (nns and range); + /// otherwise, if the tag declaration is anonymous and it is part of + /// a typedef or alias, it points to the TypedefNameDecl (used for mangling); + /// otherwise, if the tag declaration is anonymous and it is used as a + /// declaration specifier for variables, it points to the first VarDecl (used + /// for mangling); + /// otherwise, it is a null (TypedefNameDecl) pointer. + llvm::PointerUnion<TypedefNameDecl *, ExtInfo *> TypedefNameDeclOrQualifier; + + bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo *>(); } + ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo *>(); } + const ExtInfo *getExtInfo() const { + return TypedefNameDeclOrQualifier.get<ExtInfo *>(); + } + +protected: + TagDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, TagDecl *PrevDecl, + SourceLocation StartL); + + using redeclarable_base = Redeclarable<TagDecl>; + + TagDecl *getNextRedeclarationImpl() override { + return getNextRedeclaration(); + } + + TagDecl *getPreviousDeclImpl() override { + return getPreviousDecl(); + } + + TagDecl *getMostRecentDeclImpl() override { + return getMostRecentDecl(); + } + + /// Completes the definition of this tag declaration. + /// + /// This is a helper function for derived classes. + void completeDefinition(); + + /// True if this decl is currently being defined. + void setBeingDefined(bool V = true) { TagDeclBits.IsBeingDefined = V; } + + /// Indicates whether it is possible for declarations of this kind + /// to have an out-of-date definition. + /// + /// This option is only enabled when modules are enabled. + void setMayHaveOutOfDateDef(bool V = true) { + TagDeclBits.MayHaveOutOfDateDef = V; + } + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + + using redecl_range = redeclarable_base::redecl_range; + using redecl_iterator = redeclarable_base::redecl_iterator; + + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::redecls; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; + + SourceRange getBraceRange() const { return BraceRange; } + void setBraceRange(SourceRange R) { BraceRange = R; } + + /// Return SourceLocation representing start of source + /// range ignoring outer template declarations. + SourceLocation getInnerLocStart() const { return getBeginLoc(); } + + /// Return SourceLocation representing start of source + /// range taking into account any outer template declarations. + SourceLocation getOuterLocStart() const; + SourceRange getSourceRange() const override LLVM_READONLY; + + TagDecl *getCanonicalDecl() override; + const TagDecl *getCanonicalDecl() const { + return const_cast<TagDecl*>(this)->getCanonicalDecl(); + } + + /// Return true if this declaration is a completion definition of the type. + /// Provided for consistency. + bool isThisDeclarationADefinition() const { + return isCompleteDefinition(); + } + + /// Return true if this decl has its body fully specified. + bool isCompleteDefinition() const { return TagDeclBits.IsCompleteDefinition; } + + /// True if this decl has its body fully specified. + void setCompleteDefinition(bool V = true) { + TagDeclBits.IsCompleteDefinition = V; + } + + /// Return true if this complete decl is + /// required to be complete for some existing use. + bool isCompleteDefinitionRequired() const { + return TagDeclBits.IsCompleteDefinitionRequired; + } + + /// True if this complete decl is + /// required to be complete for some existing use. + void setCompleteDefinitionRequired(bool V = true) { + TagDeclBits.IsCompleteDefinitionRequired = V; + } + + /// Return true if this decl is currently being defined. + bool isBeingDefined() const { return TagDeclBits.IsBeingDefined; } + + /// True if this tag declaration is "embedded" (i.e., defined or declared + /// for the very first time) in the syntax of a declarator. + bool isEmbeddedInDeclarator() const { + return TagDeclBits.IsEmbeddedInDeclarator; + } + + /// True if this tag declaration is "embedded" (i.e., defined or declared + /// for the very first time) in the syntax of a declarator. + void setEmbeddedInDeclarator(bool isInDeclarator) { + TagDeclBits.IsEmbeddedInDeclarator = isInDeclarator; + } + + /// True if this tag is free standing, e.g. "struct foo;". + bool isFreeStanding() const { return TagDeclBits.IsFreeStanding; } + + /// True if this tag is free standing, e.g. "struct foo;". + void setFreeStanding(bool isFreeStanding = true) { + TagDeclBits.IsFreeStanding = isFreeStanding; + } + + /// Indicates whether it is possible for declarations of this kind + /// to have an out-of-date definition. + /// + /// This option is only enabled when modules are enabled. + bool mayHaveOutOfDateDef() const { return TagDeclBits.MayHaveOutOfDateDef; } + + /// Whether this declaration declares a type that is + /// dependent, i.e., a type that somehow depends on template + /// parameters. + bool isDependentType() const { return isDependentContext(); } + + /// Starts the definition of this tag declaration. + /// + /// This method should be invoked at the beginning of the definition + /// of this tag declaration. It will set the tag type into a state + /// where it is in the process of being defined. + void startDefinition(); + + /// Returns the TagDecl that actually defines this + /// struct/union/class/enum. When determining whether or not a + /// struct/union/class/enum has a definition, one should use this + /// method as opposed to 'isDefinition'. 'isDefinition' indicates + /// whether or not a specific TagDecl is defining declaration, not + /// whether or not the struct/union/class/enum type is defined. + /// This method returns NULL if there is no TagDecl that defines + /// the struct/union/class/enum. + TagDecl *getDefinition() const; + + StringRef getKindName() const { + return TypeWithKeyword::getTagTypeKindName(getTagKind()); + } + + TagKind getTagKind() const { + return static_cast<TagKind>(TagDeclBits.TagDeclKind); + } + + void setTagKind(TagKind TK) { TagDeclBits.TagDeclKind = TK; } + + bool isStruct() const { return getTagKind() == TTK_Struct; } + bool isInterface() const { return getTagKind() == TTK_Interface; } + bool isClass() const { return getTagKind() == TTK_Class; } + bool isUnion() const { return getTagKind() == TTK_Union; } + bool isEnum() const { return getTagKind() == TTK_Enum; } + + /// Is this tag type named, either directly or via being defined in + /// a typedef of this type? + /// + /// C++11 [basic.link]p8: + /// A type is said to have linkage if and only if: + /// - it is a class or enumeration type that is named (or has a + /// name for linkage purposes) and the name has linkage; ... + /// C++11 [dcl.typedef]p9: + /// If the typedef declaration defines an unnamed class (or enum), + /// the first typedef-name declared by the declaration to be that + /// class type (or enum type) is used to denote the class type (or + /// enum type) for linkage purposes only. + /// + /// C does not have an analogous rule, but the same concept is + /// nonetheless useful in some places. + bool hasNameForLinkage() const { + return (getDeclName() || getTypedefNameForAnonDecl()); + } + + TypedefNameDecl *getTypedefNameForAnonDecl() const { + return hasExtInfo() ? nullptr + : TypedefNameDeclOrQualifier.get<TypedefNameDecl *>(); + } + + void setTypedefNameForAnonDecl(TypedefNameDecl *TDD); + + /// Retrieve the nested-name-specifier that qualifies the name of this + /// declaration, if it was present in the source. + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() + : nullptr; + } + + /// Retrieve the nested-name-specifier (with source-location + /// information) that qualifies the name of this declaration, if it was + /// present in the source. + NestedNameSpecifierLoc getQualifierLoc() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc + : NestedNameSpecifierLoc(); + } + + void setQualifierInfo(NestedNameSpecifierLoc QualifierLoc); + + unsigned getNumTemplateParameterLists() const { + return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; + } + + TemplateParameterList *getTemplateParameterList(unsigned i) const { + assert(i < getNumTemplateParameterLists()); + return getExtInfo()->TemplParamLists[i]; + } + + void setTemplateParameterListsInfo(ASTContext &Context, + ArrayRef<TemplateParameterList *> TPLists); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K >= firstTag && K <= lastTag; } + + static DeclContext *castToDeclContext(const TagDecl *D) { + return static_cast<DeclContext *>(const_cast<TagDecl*>(D)); + } + + static TagDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TagDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// Represents an enum. In C++11, enums can be forward-declared +/// with a fixed underlying type, and in C we allow them to be forward-declared +/// with no underlying type as an extension. +class EnumDecl : public TagDecl { + // This class stores some data in DeclContext::EnumDeclBits + // to save some space. Use the provided accessors to access it. + + /// This represent the integer type that the enum corresponds + /// to for code generation purposes. Note that the enumerator constants may + /// have a different type than this does. + /// + /// If the underlying integer type was explicitly stated in the source + /// code, this is a TypeSourceInfo* for that type. Otherwise this type + /// was automatically deduced somehow, and this is a Type*. + /// + /// Normally if IsFixed(), this would contain a TypeSourceInfo*, but in + /// some cases it won't. + /// + /// The underlying type of an enumeration never has any qualifiers, so + /// we can get away with just storing a raw Type*, and thus save an + /// extra pointer when TypeSourceInfo is needed. + llvm::PointerUnion<const Type *, TypeSourceInfo *> IntegerType; + + /// The integer type that values of this type should + /// promote to. In C, enumerators are generally of an integer type + /// directly, but gcc-style large enumerators (and all enumerators + /// in C++) are of the enum type instead. + QualType PromotionType; + + /// If this enumeration is an instantiation of a member enumeration + /// of a class template specialization, this is the member specialization + /// information. + MemberSpecializationInfo *SpecializationInfo = nullptr; + + /// Store the ODRHash after first calculation. + /// The corresponding flag HasODRHash is in EnumDeclBits + /// and can be accessed with the provided accessors. + unsigned ODRHash; + + EnumDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, + bool Scoped, bool ScopedUsingClassTag, bool Fixed); + + void anchor() override; + + void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, + TemplateSpecializationKind TSK); + + /// Sets the width in bits required to store all the + /// non-negative enumerators of this enum. + void setNumPositiveBits(unsigned Num) { + EnumDeclBits.NumPositiveBits = Num; + assert(EnumDeclBits.NumPositiveBits == Num && "can't store this bitcount"); + } + + /// Returns the width in bits required to store all the + /// negative enumerators of this enum. (see getNumNegativeBits) + void setNumNegativeBits(unsigned Num) { EnumDeclBits.NumNegativeBits = Num; } + + /// True if this tag declaration is a scoped enumeration. Only + /// possible in C++11 mode. + void setScoped(bool Scoped = true) { EnumDeclBits.IsScoped = Scoped; } + + /// If this tag declaration is a scoped enum, + /// then this is true if the scoped enum was declared using the class + /// tag, false if it was declared with the struct tag. No meaning is + /// associated if this tag declaration is not a scoped enum. + void setScopedUsingClassTag(bool ScopedUCT = true) { + EnumDeclBits.IsScopedUsingClassTag = ScopedUCT; + } + + /// True if this is an Objective-C, C++11, or + /// Microsoft-style enumeration with a fixed underlying type. + void setFixed(bool Fixed = true) { EnumDeclBits.IsFixed = Fixed; } + + /// True if a valid hash is stored in ODRHash. + bool hasODRHash() const { return EnumDeclBits.HasODRHash; } + void setHasODRHash(bool Hash = true) { EnumDeclBits.HasODRHash = Hash; } + +public: + friend class ASTDeclReader; + + EnumDecl *getCanonicalDecl() override { + return cast<EnumDecl>(TagDecl::getCanonicalDecl()); + } + const EnumDecl *getCanonicalDecl() const { + return const_cast<EnumDecl*>(this)->getCanonicalDecl(); + } + + EnumDecl *getPreviousDecl() { + return cast_or_null<EnumDecl>( + static_cast<TagDecl *>(this)->getPreviousDecl()); + } + const EnumDecl *getPreviousDecl() const { + return const_cast<EnumDecl*>(this)->getPreviousDecl(); + } + + EnumDecl *getMostRecentDecl() { + return cast<EnumDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl()); + } + const EnumDecl *getMostRecentDecl() const { + return const_cast<EnumDecl*>(this)->getMostRecentDecl(); + } + + EnumDecl *getDefinition() const { + return cast_or_null<EnumDecl>(TagDecl::getDefinition()); + } + + static EnumDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, EnumDecl *PrevDecl, + bool IsScoped, bool IsScopedUsingClassTag, + bool IsFixed); + static EnumDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// When created, the EnumDecl corresponds to a + /// forward-declared enum. This method is used to mark the + /// declaration as being defined; its enumerators have already been + /// added (via DeclContext::addDecl). NewType is the new underlying + /// type of the enumeration type. + void completeDefinition(QualType NewType, + QualType PromotionType, + unsigned NumPositiveBits, + unsigned NumNegativeBits); + + // Iterates through the enumerators of this enumeration. + using enumerator_iterator = specific_decl_iterator<EnumConstantDecl>; + using enumerator_range = + llvm::iterator_range<specific_decl_iterator<EnumConstantDecl>>; + + enumerator_range enumerators() const { + return enumerator_range(enumerator_begin(), enumerator_end()); + } + + enumerator_iterator enumerator_begin() const { + const EnumDecl *E = getDefinition(); + if (!E) + E = this; + return enumerator_iterator(E->decls_begin()); + } + + enumerator_iterator enumerator_end() const { + const EnumDecl *E = getDefinition(); + if (!E) + E = this; + return enumerator_iterator(E->decls_end()); + } + + /// Return the integer type that enumerators should promote to. + QualType getPromotionType() const { return PromotionType; } + + /// Set the promotion type. + void setPromotionType(QualType T) { PromotionType = T; } + + /// Return the integer type this enum decl corresponds to. + /// This returns a null QualType for an enum forward definition with no fixed + /// underlying type. + QualType getIntegerType() const { + if (!IntegerType) + return QualType(); + if (const Type *T = IntegerType.dyn_cast<const Type*>()) + return QualType(T, 0); + return IntegerType.get<TypeSourceInfo*>()->getType().getUnqualifiedType(); + } + + /// Set the underlying integer type. + void setIntegerType(QualType T) { IntegerType = T.getTypePtrOrNull(); } + + /// Set the underlying integer type source info. + void setIntegerTypeSourceInfo(TypeSourceInfo *TInfo) { IntegerType = TInfo; } + + /// Return the type source info for the underlying integer type, + /// if no type source info exists, return 0. + TypeSourceInfo *getIntegerTypeSourceInfo() const { + return IntegerType.dyn_cast<TypeSourceInfo*>(); + } + + /// Retrieve the source range that covers the underlying type if + /// specified. + SourceRange getIntegerTypeRange() const LLVM_READONLY; + + /// Returns the width in bits required to store all the + /// non-negative enumerators of this enum. + unsigned getNumPositiveBits() const { return EnumDeclBits.NumPositiveBits; } + + /// Returns the width in bits required to store all the + /// negative enumerators of this enum. These widths include + /// the rightmost leading 1; that is: + /// + /// MOST NEGATIVE ENUMERATOR PATTERN NUM NEGATIVE BITS + /// ------------------------ ------- ----------------- + /// -1 1111111 1 + /// -10 1110110 5 + /// -101 1001011 8 + unsigned getNumNegativeBits() const { return EnumDeclBits.NumNegativeBits; } + + /// Returns true if this is a C++11 scoped enumeration. + bool isScoped() const { return EnumDeclBits.IsScoped; } + + /// Returns true if this is a C++11 scoped enumeration. + bool isScopedUsingClassTag() const { + return EnumDeclBits.IsScopedUsingClassTag; + } + + /// Returns true if this is an Objective-C, C++11, or + /// Microsoft-style enumeration with a fixed underlying type. + bool isFixed() const { return EnumDeclBits.IsFixed; } + + unsigned getODRHash(); + + /// Returns true if this can be considered a complete type. + bool isComplete() const { + // IntegerType is set for fixed type enums and non-fixed but implicitly + // int-sized Microsoft enums. + return isCompleteDefinition() || IntegerType; + } + + /// Returns true if this enum is either annotated with + /// enum_extensibility(closed) or isn't annotated with enum_extensibility. + bool isClosed() const; + + /// Returns true if this enum is annotated with flag_enum and isn't annotated + /// with enum_extensibility(open). + bool isClosedFlag() const; + + /// Returns true if this enum is annotated with neither flag_enum nor + /// enum_extensibility(open). + bool isClosedNonFlag() const; + + /// Retrieve the enum definition from which this enumeration could + /// be instantiated, if it is an instantiation (rather than a non-template). + EnumDecl *getTemplateInstantiationPattern() const; + + /// Returns the enumeration (declared within the template) + /// from which this enumeration type was instantiated, or NULL if + /// this enumeration was not instantiated from any template. + EnumDecl *getInstantiatedFromMemberEnum() const; + + /// If this enumeration is a member of a specialization of a + /// templated class, determine what kind of template specialization + /// or instantiation this is. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// For an enumeration member that was instantiated from a member + /// enumeration of a templated class, set the template specialiation kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// If this enumeration is an instantiation of a member enumeration of + /// a class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const { + return SpecializationInfo; + } + + /// Specify that this enumeration is an instantiation of the + /// member enumeration ED. + void setInstantiationOfMemberEnum(EnumDecl *ED, + TemplateSpecializationKind TSK) { + setInstantiationOfMemberEnum(getASTContext(), ED, TSK); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Enum; } +}; + +/// Represents a struct/union/class. For example: +/// struct X; // Forward declaration, no "body". +/// union Y { int A, B; }; // Has body with members A and B (FieldDecls). +/// This decl will be marked invalid if *any* members are invalid. +class RecordDecl : public TagDecl { + // This class stores some data in DeclContext::RecordDeclBits + // to save some space. Use the provided accessors to access it. +public: + friend class DeclContext; + /// Enum that represents the different ways arguments are passed to and + /// returned from function calls. This takes into account the target-specific + /// and version-specific rules along with the rules determined by the + /// language. + enum ArgPassingKind : unsigned { + /// The argument of this type can be passed directly in registers. + APK_CanPassInRegs, + + /// The argument of this type cannot be passed directly in registers. + /// Records containing this type as a subobject are not forced to be passed + /// indirectly. This value is used only in C++. This value is required by + /// C++ because, in uncommon situations, it is possible for a class to have + /// only trivial copy/move constructors even when one of its subobjects has + /// a non-trivial copy/move constructor (if e.g. the corresponding copy/move + /// constructor in the derived class is deleted). + APK_CannotPassInRegs, + + /// The argument of this type cannot be passed directly in registers. + /// Records containing this type as a subobject are forced to be passed + /// indirectly. + APK_CanNeverPassInRegs + }; + +protected: + RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl *PrevDecl); + +public: + static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl* PrevDecl = nullptr); + static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); + + RecordDecl *getPreviousDecl() { + return cast_or_null<RecordDecl>( + static_cast<TagDecl *>(this)->getPreviousDecl()); + } + const RecordDecl *getPreviousDecl() const { + return const_cast<RecordDecl*>(this)->getPreviousDecl(); + } + + RecordDecl *getMostRecentDecl() { + return cast<RecordDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl()); + } + const RecordDecl *getMostRecentDecl() const { + return const_cast<RecordDecl*>(this)->getMostRecentDecl(); + } + + bool hasFlexibleArrayMember() const { + return RecordDeclBits.HasFlexibleArrayMember; + } + + void setHasFlexibleArrayMember(bool V) { + RecordDeclBits.HasFlexibleArrayMember = V; + } + + /// Whether this is an anonymous struct or union. To be an anonymous + /// struct or union, it must have been declared without a name and + /// there must be no objects of this type declared, e.g., + /// @code + /// union { int i; float f; }; + /// @endcode + /// is an anonymous union but neither of the following are: + /// @code + /// union X { int i; float f; }; + /// union { int i; float f; } obj; + /// @endcode + bool isAnonymousStructOrUnion() const { + return RecordDeclBits.AnonymousStructOrUnion; + } + + void setAnonymousStructOrUnion(bool Anon) { + RecordDeclBits.AnonymousStructOrUnion = Anon; + } + + bool hasObjectMember() const { return RecordDeclBits.HasObjectMember; } + void setHasObjectMember(bool val) { RecordDeclBits.HasObjectMember = val; } + + bool hasVolatileMember() const { return RecordDeclBits.HasVolatileMember; } + + void setHasVolatileMember(bool val) { + RecordDeclBits.HasVolatileMember = val; + } + + bool hasLoadedFieldsFromExternalStorage() const { + return RecordDeclBits.LoadedFieldsFromExternalStorage; + } + + void setHasLoadedFieldsFromExternalStorage(bool val) const { + RecordDeclBits.LoadedFieldsFromExternalStorage = val; + } + + /// Functions to query basic properties of non-trivial C structs. + bool isNonTrivialToPrimitiveDefaultInitialize() const { + return RecordDeclBits.NonTrivialToPrimitiveDefaultInitialize; + } + + void setNonTrivialToPrimitiveDefaultInitialize(bool V) { + RecordDeclBits.NonTrivialToPrimitiveDefaultInitialize = V; + } + + bool isNonTrivialToPrimitiveCopy() const { + return RecordDeclBits.NonTrivialToPrimitiveCopy; + } + + void setNonTrivialToPrimitiveCopy(bool V) { + RecordDeclBits.NonTrivialToPrimitiveCopy = V; + } + + bool isNonTrivialToPrimitiveDestroy() const { + return RecordDeclBits.NonTrivialToPrimitiveDestroy; + } + + void setNonTrivialToPrimitiveDestroy(bool V) { + RecordDeclBits.NonTrivialToPrimitiveDestroy = V; + } + + /// Determine whether this class can be passed in registers. In C++ mode, + /// it must have at least one trivial, non-deleted copy or move constructor. + /// FIXME: This should be set as part of completeDefinition. + bool canPassInRegisters() const { + return getArgPassingRestrictions() == APK_CanPassInRegs; + } + + ArgPassingKind getArgPassingRestrictions() const { + return static_cast<ArgPassingKind>(RecordDeclBits.ArgPassingRestrictions); + } + + void setArgPassingRestrictions(ArgPassingKind Kind) { + RecordDeclBits.ArgPassingRestrictions = Kind; + } + + bool isParamDestroyedInCallee() const { + return RecordDeclBits.ParamDestroyedInCallee; + } + + void setParamDestroyedInCallee(bool V) { + RecordDeclBits.ParamDestroyedInCallee = V; + } + + /// Determines whether this declaration represents the + /// injected class name. + /// + /// The injected class name in C++ is the name of the class that + /// appears inside the class itself. For example: + /// + /// \code + /// struct C { + /// // C is implicitly declared here as a synonym for the class name. + /// }; + /// + /// C::C c; // same as "C c;" + /// \endcode + bool isInjectedClassName() const; + + /// Determine whether this record is a class describing a lambda + /// function object. + bool isLambda() const; + + /// Determine whether this record is a record for captured variables in + /// CapturedStmt construct. + bool isCapturedRecord() const; + + /// Mark the record as a record for captured variables in CapturedStmt + /// construct. + void setCapturedRecord(); + + /// Returns the RecordDecl that actually defines + /// this struct/union/class. When determining whether or not a + /// struct/union/class is completely defined, one should use this + /// method as opposed to 'isCompleteDefinition'. + /// 'isCompleteDefinition' indicates whether or not a specific + /// RecordDecl is a completed definition, not whether or not the + /// record type is defined. This method returns NULL if there is + /// no RecordDecl that defines the struct/union/tag. + RecordDecl *getDefinition() const { + return cast_or_null<RecordDecl>(TagDecl::getDefinition()); + } + + // Iterator access to field members. The field iterator only visits + // the non-static data members of this class, ignoring any static + // data members, functions, constructors, destructors, etc. + using field_iterator = specific_decl_iterator<FieldDecl>; + using field_range = llvm::iterator_range<specific_decl_iterator<FieldDecl>>; + + field_range fields() const { return field_range(field_begin(), field_end()); } + field_iterator field_begin() const; + + field_iterator field_end() const { + return field_iterator(decl_iterator()); + } + + // Whether there are any fields (non-static data members) in this record. + bool field_empty() const { + return field_begin() == field_end(); + } + + /// Note that the definition of this type is now complete. + virtual void completeDefinition(); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstRecord && K <= lastRecord; + } + + /// Get whether or not this is an ms_struct which can + /// be turned on with an attribute, pragma, or -mms-bitfields + /// commandline option. + bool isMsStruct(const ASTContext &C) const; + + /// Whether we are allowed to insert extra padding between fields. + /// These padding are added to help AddressSanitizer detect + /// intra-object-overflow bugs. + bool mayInsertExtraPadding(bool EmitRemark = false) const; + + /// Finds the first data member which has a name. + /// nullptr is returned if no named data member exists. + const FieldDecl *findFirstNamedDataMember() const; + +private: + /// Deserialize just the fields. + void LoadFieldsFromExternalStorage() const; +}; + +class FileScopeAsmDecl : public Decl { + StringLiteral *AsmString; + SourceLocation RParenLoc; + + FileScopeAsmDecl(DeclContext *DC, StringLiteral *asmstring, + SourceLocation StartL, SourceLocation EndL) + : Decl(FileScopeAsm, DC, StartL), AsmString(asmstring), RParenLoc(EndL) {} + + virtual void anchor(); + +public: + static FileScopeAsmDecl *Create(ASTContext &C, DeclContext *DC, + StringLiteral *Str, SourceLocation AsmLoc, + SourceLocation RParenLoc); + + static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getAsmLoc() const { return getLocation(); } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getAsmLoc(), getRParenLoc()); + } + + const StringLiteral *getAsmString() const { return AsmString; } + StringLiteral *getAsmString() { return AsmString; } + void setAsmString(StringLiteral *Asm) { AsmString = Asm; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == FileScopeAsm; } +}; + +/// Represents a block literal declaration, which is like an +/// unnamed FunctionDecl. For example: +/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } +class BlockDecl : public Decl, public DeclContext { + // This class stores some data in DeclContext::BlockDeclBits + // to save some space. Use the provided accessors to access it. +public: + /// A class which contains all the information about a particular + /// captured value. + class Capture { + enum { + flag_isByRef = 0x1, + flag_isNested = 0x2 + }; + + /// The variable being captured. + llvm::PointerIntPair<VarDecl*, 2> VariableAndFlags; + + /// The copy expression, expressed in terms of a DeclRef (or + /// BlockDeclRef) to the captured variable. Only required if the + /// variable has a C++ class type. + Expr *CopyExpr; + + public: + Capture(VarDecl *variable, bool byRef, bool nested, Expr *copy) + : VariableAndFlags(variable, + (byRef ? flag_isByRef : 0) | (nested ? flag_isNested : 0)), + CopyExpr(copy) {} + + /// The variable being captured. + VarDecl *getVariable() const { return VariableAndFlags.getPointer(); } + + /// Whether this is a "by ref" capture, i.e. a capture of a __block + /// variable. + bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; } + + bool isEscapingByref() const { + return getVariable()->isEscapingByref(); + } + + bool isNonEscapingByref() const { + return getVariable()->isNonEscapingByref(); + } + + /// Whether this is a nested capture, i.e. the variable captured + /// is not from outside the immediately enclosing function/block. + bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; } + + bool hasCopyExpr() const { return CopyExpr != nullptr; } + Expr *getCopyExpr() const { return CopyExpr; } + void setCopyExpr(Expr *e) { CopyExpr = e; } + }; + +private: + /// A new[]'d array of pointers to ParmVarDecls for the formal + /// parameters of this function. This is null if a prototype or if there are + /// no formals. + ParmVarDecl **ParamInfo = nullptr; + unsigned NumParams = 0; + + Stmt *Body = nullptr; + TypeSourceInfo *SignatureAsWritten = nullptr; + + const Capture *Captures = nullptr; + unsigned NumCaptures = 0; + + unsigned ManglingNumber = 0; + Decl *ManglingContextDecl = nullptr; + +protected: + BlockDecl(DeclContext *DC, SourceLocation CaretLoc); + +public: + static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); + static BlockDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getCaretLocation() const { return getLocation(); } + + bool isVariadic() const { return BlockDeclBits.IsVariadic; } + void setIsVariadic(bool value) { BlockDeclBits.IsVariadic = value; } + + CompoundStmt *getCompoundBody() const { return (CompoundStmt*) Body; } + Stmt *getBody() const override { return (Stmt*) Body; } + void setBody(CompoundStmt *B) { Body = (Stmt*) B; } + + void setSignatureAsWritten(TypeSourceInfo *Sig) { SignatureAsWritten = Sig; } + TypeSourceInfo *getSignatureAsWritten() const { return SignatureAsWritten; } + + // ArrayRef access to formal parameters. + ArrayRef<ParmVarDecl *> parameters() const { + return {ParamInfo, getNumParams()}; + } + MutableArrayRef<ParmVarDecl *> parameters() { + return {ParamInfo, getNumParams()}; + } + + // Iterator access to formal parameters. + using param_iterator = MutableArrayRef<ParmVarDecl *>::iterator; + using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator; + + bool param_empty() const { return parameters().empty(); } + param_iterator param_begin() { return parameters().begin(); } + param_iterator param_end() { return parameters().end(); } + param_const_iterator param_begin() const { return parameters().begin(); } + param_const_iterator param_end() const { return parameters().end(); } + size_t param_size() const { return parameters().size(); } + + unsigned getNumParams() const { return NumParams; } + + const ParmVarDecl *getParamDecl(unsigned i) const { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + + void setParams(ArrayRef<ParmVarDecl *> NewParamInfo); + + /// True if this block (or its nested blocks) captures + /// anything of local storage from its enclosing scopes. + bool hasCaptures() const { return NumCaptures || capturesCXXThis(); } + + /// Returns the number of captured variables. + /// Does not include an entry for 'this'. + unsigned getNumCaptures() const { return NumCaptures; } + + using capture_const_iterator = ArrayRef<Capture>::const_iterator; + + ArrayRef<Capture> captures() const { return {Captures, NumCaptures}; } + + capture_const_iterator capture_begin() const { return captures().begin(); } + capture_const_iterator capture_end() const { return captures().end(); } + + bool capturesCXXThis() const { return BlockDeclBits.CapturesCXXThis; } + void setCapturesCXXThis(bool B = true) { BlockDeclBits.CapturesCXXThis = B; } + + bool blockMissingReturnType() const { + return BlockDeclBits.BlockMissingReturnType; + } + + void setBlockMissingReturnType(bool val = true) { + BlockDeclBits.BlockMissingReturnType = val; + } + + bool isConversionFromLambda() const { + return BlockDeclBits.IsConversionFromLambda; + } + + void setIsConversionFromLambda(bool val = true) { + BlockDeclBits.IsConversionFromLambda = val; + } + + bool doesNotEscape() const { return BlockDeclBits.DoesNotEscape; } + void setDoesNotEscape(bool B = true) { BlockDeclBits.DoesNotEscape = B; } + + bool capturesVariable(const VarDecl *var) const; + + void setCaptures(ASTContext &Context, ArrayRef<Capture> Captures, + bool CapturesCXXThis); + + unsigned getBlockManglingNumber() const { + return ManglingNumber; + } + + Decl *getBlockManglingContextDecl() const { + return ManglingContextDecl; + } + + void setBlockMangling(unsigned Number, Decl *Ctx) { + ManglingNumber = Number; + ManglingContextDecl = Ctx; + } + + SourceRange getSourceRange() const override LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Block; } + static DeclContext *castToDeclContext(const BlockDecl *D) { + return static_cast<DeclContext *>(const_cast<BlockDecl*>(D)); + } + static BlockDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<BlockDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// Represents the body of a CapturedStmt, and serves as its DeclContext. +class CapturedDecl final + : public Decl, + public DeclContext, + private llvm::TrailingObjects<CapturedDecl, ImplicitParamDecl *> { +protected: + size_t numTrailingObjects(OverloadToken<ImplicitParamDecl>) { + return NumParams; + } + +private: + /// The number of parameters to the outlined function. + unsigned NumParams; + + /// The position of context parameter in list of parameters. + unsigned ContextParam; + + /// The body of the outlined function. + llvm::PointerIntPair<Stmt *, 1, bool> BodyAndNothrow; + + explicit CapturedDecl(DeclContext *DC, unsigned NumParams); + + ImplicitParamDecl *const *getParams() const { + return getTrailingObjects<ImplicitParamDecl *>(); + } + + ImplicitParamDecl **getParams() { + return getTrailingObjects<ImplicitParamDecl *>(); + } + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; + + static CapturedDecl *Create(ASTContext &C, DeclContext *DC, + unsigned NumParams); + static CapturedDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumParams); + + Stmt *getBody() const override; + void setBody(Stmt *B); + + bool isNothrow() const; + void setNothrow(bool Nothrow = true); + + unsigned getNumParams() const { return NumParams; } + + ImplicitParamDecl *getParam(unsigned i) const { + assert(i < NumParams); + return getParams()[i]; + } + void setParam(unsigned i, ImplicitParamDecl *P) { + assert(i < NumParams); + getParams()[i] = P; + } + + // ArrayRef interface to parameters. + ArrayRef<ImplicitParamDecl *> parameters() const { + return {getParams(), getNumParams()}; + } + MutableArrayRef<ImplicitParamDecl *> parameters() { + return {getParams(), getNumParams()}; + } + + /// Retrieve the parameter containing captured variables. + ImplicitParamDecl *getContextParam() const { + assert(ContextParam < NumParams); + return getParam(ContextParam); + } + void setContextParam(unsigned i, ImplicitParamDecl *P) { + assert(i < NumParams); + ContextParam = i; + setParam(i, P); + } + unsigned getContextParamPosition() const { return ContextParam; } + + using param_iterator = ImplicitParamDecl *const *; + using param_range = llvm::iterator_range<param_iterator>; + + /// Retrieve an iterator pointing to the first parameter decl. + param_iterator param_begin() const { return getParams(); } + /// Retrieve an iterator one past the last parameter decl. + param_iterator param_end() const { return getParams() + NumParams; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Captured; } + static DeclContext *castToDeclContext(const CapturedDecl *D) { + return static_cast<DeclContext *>(const_cast<CapturedDecl *>(D)); + } + static CapturedDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<CapturedDecl *>(const_cast<DeclContext *>(DC)); + } +}; + +/// Describes a module import declaration, which makes the contents +/// of the named module visible in the current translation unit. +/// +/// An import declaration imports the named module (or submodule). For example: +/// \code +/// @import std.vector; +/// \endcode +/// +/// Import declarations can also be implicitly generated from +/// \#include/\#import directives. +class ImportDecl final : public Decl, + llvm::TrailingObjects<ImportDecl, SourceLocation> { + friend class ASTContext; + friend class ASTDeclReader; + friend class ASTReader; + friend TrailingObjects; + + /// The imported module, along with a bit that indicates whether + /// we have source-location information for each identifier in the module + /// name. + /// + /// When the bit is false, we only have a single source location for the + /// end of the import declaration. + llvm::PointerIntPair<Module *, 1, bool> ImportedAndComplete; + + /// The next import in the list of imports local to the translation + /// unit being parsed (not loaded from an AST file). + ImportDecl *NextLocalImport = nullptr; + + ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, + ArrayRef<SourceLocation> IdentifierLocs); + + ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, + SourceLocation EndLoc); + + ImportDecl(EmptyShell Empty) : Decl(Import, Empty) {} + +public: + /// Create a new module import declaration. + static ImportDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, Module *Imported, + ArrayRef<SourceLocation> IdentifierLocs); + + /// Create a new module import declaration for an implicitly-generated + /// import. + static ImportDecl *CreateImplicit(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, Module *Imported, + SourceLocation EndLoc); + + /// Create a new, deserialized module import declaration. + static ImportDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumLocations); + + /// Retrieve the module that was imported by the import declaration. + Module *getImportedModule() const { return ImportedAndComplete.getPointer(); } + + /// Retrieves the locations of each of the identifiers that make up + /// the complete module name in the import declaration. + /// + /// This will return an empty array if the locations of the individual + /// identifiers aren't available. + ArrayRef<SourceLocation> getIdentifierLocs() const; + + SourceRange getSourceRange() const override LLVM_READONLY; + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Import; } +}; + +/// Represents a C++ Modules TS module export declaration. +/// +/// For example: +/// \code +/// export void foo(); +/// \endcode +class ExportDecl final : public Decl, public DeclContext { + virtual void anchor(); + +private: + friend class ASTDeclReader; + + /// The source location for the right brace (if valid). + SourceLocation RBraceLoc; + + ExportDecl(DeclContext *DC, SourceLocation ExportLoc) + : Decl(Export, DC, ExportLoc), DeclContext(Export), + RBraceLoc(SourceLocation()) {} + +public: + static ExportDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation ExportLoc); + static ExportDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getExportLoc() const { return getLocation(); } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + + SourceLocation getEndLoc() const LLVM_READONLY { + if (RBraceLoc.isValid()) + return RBraceLoc; + // No braces: get the end location of the (only) declaration in context + // (if present). + return decls_empty() ? getLocation() : decls_begin()->getEndLoc(); + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getLocation(), getEndLoc()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Export; } + static DeclContext *castToDeclContext(const ExportDecl *D) { + return static_cast<DeclContext *>(const_cast<ExportDecl*>(D)); + } + static ExportDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ExportDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// Represents an empty-declaration. +class EmptyDecl : public Decl { + EmptyDecl(DeclContext *DC, SourceLocation L) : Decl(Empty, DC, L) {} + + virtual void anchor(); + +public: + static EmptyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L); + static EmptyDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Empty; } +}; + +/// Insertion operator for diagnostics. This allows sending NamedDecl's +/// into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const NamedDecl* ND) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND), + DiagnosticsEngine::ak_nameddecl); + return DB; +} +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const NamedDecl* ND) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(ND), + DiagnosticsEngine::ak_nameddecl); + return PD; +} + +template<typename decl_type> +void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) { + // Note: This routine is implemented here because we need both NamedDecl + // and Redeclarable to be defined. + assert(RedeclLink.isFirst() && + "setPreviousDecl on a decl already in a redeclaration chain"); + + if (PrevDecl) { + // Point to previous. Make sure that this is actually the most recent + // redeclaration, or we can build invalid chains. If the most recent + // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. + First = PrevDecl->getFirstDecl(); + assert(First->RedeclLink.isFirst() && "Expected first"); + decl_type *MostRecent = First->getNextRedeclaration(); + RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent)); + + // If the declaration was previously visible, a redeclaration of it remains + // visible even if it wouldn't be visible by itself. + static_cast<decl_type*>(this)->IdentifierNamespace |= + MostRecent->getIdentifierNamespace() & + (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type); + } else { + // Make this first. + First = static_cast<decl_type*>(this); + } + + // First one will point to this one as latest. + First->RedeclLink.setLatest(static_cast<decl_type*>(this)); + + assert(!isa<NamedDecl>(static_cast<decl_type*>(this)) || + cast<NamedDecl>(static_cast<decl_type*>(this))->isLinkageValid()); +} + +// Inline function definitions. + +/// Check if the given decl is complete. +/// +/// We use this function to break a cycle between the inline definitions in +/// Type.h and Decl.h. +inline bool IsEnumDeclComplete(EnumDecl *ED) { + return ED->isComplete(); +} + +/// Check if the given decl is scoped. +/// +/// We use this function to break a cycle between the inline definitions in +/// Type.h and Decl.h. +inline bool IsEnumDeclScoped(EnumDecl *ED) { + return ED->isScoped(); +} + +} // namespace clang + +#endif // LLVM_CLANG_AST_DECL_H |
