Index: vendor/clang/dist/include/clang/AST/Decl.h =================================================================== --- vendor/clang/dist/include/clang/AST/Decl.h (revision 318415) +++ vendor/clang/dist/include/clang/AST/Decl.h (revision 318416) @@ -1,3981 +1,3971 @@ //===--- Decl.h - Classes for representing declarations ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the Decl subclasses. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_DECL_H #define LLVM_CLANG_AST_DECL_H #include "clang/AST/APValue.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Redeclarable.h" #include "clang/AST/Type.h" #include "clang/Basic/Linkage.h" #include "clang/Basic/Module.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/PragmaKinds.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/TrailingObjects.h" namespace clang { struct ASTTemplateArgumentListInfo; class CXXTemporary; class CompoundStmt; class DependentFunctionTemplateSpecializationInfo; class Expr; class FunctionTemplateDecl; class FunctionTemplateSpecializationInfo; class LabelStmt; class MemberSpecializationInfo; class NestedNameSpecifier; class ParmVarDecl; class Stmt; class StringLiteral; class TemplateArgumentList; class TemplateParameterList; class TypeAliasTemplateDecl; class TypeLoc; class UnresolvedSetImpl; class VarTemplateDecl; /// \brief A container of type source information. /// /// A client can read the relevant info using TypeLoc wrappers, e.g: /// @code /// TypeLoc TL = TypeSourceInfo->getTypeLoc(); /// TL.getStartLoc().print(OS, SrcMgr); /// @endcode /// class TypeSourceInfo { QualType Ty; // Contains a memory block after the class, used for type source information, // allocated by ASTContext. friend class ASTContext; TypeSourceInfo(QualType ty) : Ty(ty) { } public: /// \brief Return the type wrapped by this type source info. QualType getType() const { return Ty; } /// \brief Return the TypeLoc wrapper for the type source info. TypeLoc getTypeLoc() const; // implemented in TypeLoc.h /// \brief Override the type stored in this TypeSourceInfo. Use with caution! void overrideType(QualType T) { Ty = T; } }; /// TranslationUnitDecl - The top declaration context. class TranslationUnitDecl : public Decl, public DeclContext { virtual void anchor(); ASTContext &Ctx; /// The (most recently entered) anonymous namespace for this /// translation unit, if one has been created. NamespaceDecl *AnonymousNamespace; explicit TranslationUnitDecl(ASTContext &ctx); 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(const_cast(D)); } static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } }; /// \brief Represents a `#pragma comment` line. Always a child of /// TranslationUnitDecl. class PragmaCommentDecl final : public Decl, private llvm::TrailingObjects { virtual void anchor(); PragmaMSCommentKind CommentKind; friend TrailingObjects; friend class ASTDeclReader; friend class ASTDeclWriter; PragmaCommentDecl(TranslationUnitDecl *TU, SourceLocation CommentLoc, PragmaMSCommentKind CommentKind) : Decl(PragmaComment, TU, CommentLoc), CommentKind(CommentKind) {} 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(); } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == PragmaComment; } }; /// \brief Represents a `#pragma detect_mismatch` line. Always a child of /// TranslationUnitDecl. class PragmaDetectMismatchDecl final : public Decl, private llvm::TrailingObjects { virtual void anchor(); size_t ValueStart; friend TrailingObjects; friend class ASTDeclReader; friend class ASTDeclWriter; PragmaDetectMismatchDecl(TranslationUnitDecl *TU, SourceLocation Loc, size_t ValueStart) : Decl(PragmaDetectMismatch, TU, Loc), ValueStart(ValueStart) {} 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(); } StringRef getValue() const { return getTrailingObjects() + ValueStart; } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == PragmaDetectMismatch; } }; /// \brief 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 { virtual void anchor(); explicit ExternCContextDecl(TranslationUnitDecl *TU) : Decl(ExternCContext, TU, SourceLocation()), DeclContext(ExternCContext) {} 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(const_cast(D)); } static ExternCContextDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } }; /// NamedDecl - This represents a decl with a name. Many decls have names such /// as ObjCMethodDecl, but not \@class, etc. class NamedDecl : public Decl { virtual void anchor(); /// Name - 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; private: NamedDecl *getUnderlyingDeclImpl() LLVM_READONLY; protected: NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N) : Decl(DK, DC, L), Name(N) { } public: /// getIdentifier - 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(); } /// getName - 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() : ""; } /// getNameAsString - 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; /// getDeclName - Get the actual, stored name of the declaration, /// which may be a special name. DeclarationName getDeclName() const { return Name; } /// \brief Set the name of this declaration. void setDeclName(DeclarationName N) { Name = N; } /// printQualifiedName - Returns human-readable qualified name for /// declaration, like A::B::i, for i being member of namespace A::B. /// If declaration is not member of context which can be named (record, /// namespace), it will return 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; /// getNameForDiagnostic - 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; /// \brief 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; /// \brief Determine whether this declaration has linkage. bool hasLinkage() const; using Decl::isModulePrivate; using Decl::setModulePrivate; - /// \brief Determine whether this declaration is hidden from name lookup. - bool isHidden() const { return Hidden; } - - /// \brief Set whether this declaration is hidden from name lookup. - void setHidden(bool Hide) { - assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) && - "declaration with no owning module can't be hidden"); - Hidden = Hide; - } - /// \brief 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(DC)) DC = DC->getRedeclContext(); return DC->isRecord(); } /// \brief Determine whether the given declaration is an instance member of /// a C++ class. bool isCXXInstanceMember() const; /// \brief 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; /// \brief 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()); } /// \brief True if this decl has external linkage. bool hasExternalFormalLinkage() const { return isExternalFormalLinkage(getLinkageInternal()); } bool isExternallyVisible() const { return clang::isExternallyVisible(getLinkageInternal()); } /// \brief Determines the visibility of this entity. Visibility getVisibility() const { return getLinkageAndVisibility().getVisibility(); } /// \brief Determines the linkage and visibility of this entity. LinkageInfo getLinkageAndVisibility() const; /// Kinds of explicit visibility. enum ExplicitVisibilityKind { VisibilityForType, VisibilityForValue }; /// \brief If visibility was explicitly specified for this /// declaration, return that visibility. Optional getExplicitVisibility(ExplicitVisibilityKind kind) const; /// \brief True if the computed linkage is valid. Used for consistency /// checking. Should always return true. bool isLinkageValid() const; /// \brief 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(); } /// \brief 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(this)->getUnderlyingDecl(); } NamedDecl *getMostRecentDecl() { return cast(static_cast(this)->getMostRecentDecl()); } const NamedDecl *getMostRecentDecl() const { return const_cast(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; } /// LabelDecl - 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 { void anchor() override; LabelStmt *TheStmt; StringRef MSAsmName; bool MSAsmNameResolved; /// LocStart - 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), MSAsmNameResolved(false), LocStart(StartL) {} 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.size() != 0; } 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; } }; /// NamespaceDecl - Represent a C++ namespace. class NamespaceDecl : public NamedDecl, public DeclContext, public Redeclarable { /// LocStart - The starting location of the source range, pointing /// to either the namespace or the inline keyword. SourceLocation LocStart; /// RBraceLoc - The ending location of the source range. SourceLocation RBraceLoc; /// \brief 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 AnonOrFirstNamespaceAndInline; NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl); typedef Redeclarable redeclarable_base; NamespaceDecl *getNextRedeclarationImpl() override; NamespaceDecl *getPreviousDeclImpl() override; NamespaceDecl *getMostRecentDeclImpl() override; public: static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl); static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID); typedef redeclarable_base::redecl_range redecl_range; typedef redeclarable_base::redecl_iterator 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; /// \brief Returns true if this is an anonymous namespace declaration. /// /// For example: /// \code /// namespace { /// ... /// }; /// \endcode /// q.v. C++ [namespace.unnamed] bool isAnonymousNamespace() const { return !getIdentifier(); } /// \brief Returns true if this is an inline namespace declaration. bool isInline() const { return AnonOrFirstNamespaceAndInline.getInt(); } /// \brief Set whether this is an inline namespace declaration. void setInline(bool Inline) { AnonOrFirstNamespaceAndInline.setInt(Inline); } /// \brief Get the original (first) namespace declaration. NamespaceDecl *getOriginalNamespace(); /// \brief Get the original (first) namespace declaration. const NamespaceDecl *getOriginalNamespace() const; /// \brief 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; /// \brief 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 getLocStart() 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(const_cast(D)); } static NamespaceDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } friend class ASTDeclReader; friend class ASTDeclWriter; }; /// ValueDecl - 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 { void anchor() override; QualType DeclType; 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; } /// \brief 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; } }; /// QualifierInfo - 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; /// NumTemplParamLists - 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; /// TemplParamLists - 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; /// Default constructor. QualifierInfo() : QualifierLoc(), NumTemplParamLists(0), TemplParamLists(nullptr) {} /// setTemplateParameterListsInfo - Sets info about "outer" template /// parameter lists. void setTemplateParameterListsInfo(ASTContext &Context, ArrayRef TPLists); private: // Copy constructor and copy assignment are disabled. QualifierInfo(const QualifierInfo&) = delete; QualifierInfo& operator=(const QualifierInfo&) = delete; }; /// \brief 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 DeclInfo; /// InnerLocStart - The start of the source range for this declaration, /// ignoring outer template declarations. SourceLocation InnerLocStart; bool hasExtInfo() const { return DeclInfo.is(); } ExtInfo *getExtInfo() { return DeclInfo.get(); } const ExtInfo *getExtInfo() const { return DeclInfo.get(); } 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: TypeSourceInfo *getTypeSourceInfo() const { return hasExtInfo() ? getExtInfo()->TInfo : DeclInfo.get(); } void setTypeSourceInfo(TypeSourceInfo *TI) { if (hasExtInfo()) getExtInfo()->TInfo = TI; else DeclInfo = TI; } /// getInnerLocStart - Return SourceLocation representing start of source /// range ignoring outer template declarations. SourceLocation getInnerLocStart() const { return InnerLocStart; } void setInnerLocStart(SourceLocation L) { InnerLocStart = L; } /// getOuterLocStart - Return SourceLocation representing start of source /// range taking into account any outer template declarations. SourceLocation getOuterLocStart() const; SourceRange getSourceRange() const override LLVM_READONLY; SourceLocation getLocStart() const LLVM_READONLY { return getOuterLocStart(); } /// \brief 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; } /// \brief 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 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; } friend class ASTDeclReader; friend class ASTDeclWriter; }; /// \brief 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 { EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false), CheckingICE(false), IsICE(false) { } /// \brief Whether this statement was already evaluated. bool WasEvaluated : 1; /// \brief Whether this statement is being evaluated. bool IsEvaluating : 1; /// \brief Whether we already checked whether this statement was an /// integral constant expression. bool CheckedICE : 1; /// \brief Whether we are checking whether this statement is an /// integral constant expression. bool CheckingICE : 1; /// \brief 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; }; /// VarDecl - An instance of this class is created to represent a variable /// declaration or definition. class VarDecl : public DeclaratorDecl, public Redeclarable { public: /// getStorageClassSpecifierString - 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); /// \brief Initialization styles. enum InitializationStyle { CInit, ///< C-style initialization with assignment CallInit, ///< Call-style initialization (C++98) ListInit ///< Direct list-initialization (C++11) }; /// \brief Kinds of thread-local storage. enum TLSKind { TLS_None, ///< Not a TLS variable. TLS_Static, ///< TLS with a known-constant initializer. TLS_Dynamic ///< TLS with a dynamic initializer. }; 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. typedef llvm::PointerUnion InitType; /// \brief The initializer for this variable or, for a ParmVarDecl, the /// C++ default argument. mutable InitType Init; private: class VarDeclBitfields { friend class VarDecl; friend class ASTDeclReader; unsigned SClass : 3; unsigned TSCSpec : 2; unsigned InitStyle : 2; }; enum { NumVarDeclBits = 7 }; friend class ASTDeclReader; friend class StmtIteratorBase; friend class ASTNodeImporter; protected: enum { NumParameterIndexBits = 8 }; enum DefaultArgKind { DAK_None, DAK_Unparsed, DAK_Uninstantiated, DAK_Normal }; class ParmVarDeclBitfields { friend class ParmVarDecl; friend class ASTDeclReader; 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 VarDecl; friend class ASTDeclReader; unsigned : NumVarDeclBits; // FIXME: We need something similar to CXXRecordDecl::DefinitionData. /// \brief Whether this variable is a definition which was demoted due to /// module merge. unsigned IsThisDeclarationADemotedDefinition : 1; /// \brief Whether this variable is the exception variable in a C++ catch /// or an Objective-C @catch statement. unsigned ExceptionVar : 1; /// \brief Whether this local variable could be allocated in the return /// slot of its function, enabling the named return value optimization /// (NRVO). unsigned NRVOVariable : 1; /// \brief Whether this variable is the for-range-declaration in a C++0x /// for-range statement. unsigned CXXForRangeDecl : 1; /// \brief Whether this variable is an ARC pseudo-__strong /// variable; see isARCPseudoStrong() for details. unsigned ARCPseudoStrong : 1; /// \brief Whether this variable is (C++1z) inline. unsigned IsInline : 1; /// \brief Whether this variable has (C++1z) inline explicitly specified. unsigned IsInlineSpecified : 1; /// \brief Whether this variable is (C++0x) constexpr. unsigned IsConstexpr : 1; /// \brief Whether this variable is the implicit variable for a lambda /// init-capture. unsigned IsInitCapture : 1; /// \brief 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; }; 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); typedef Redeclarable redeclarable_base; VarDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } VarDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } VarDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } public: typedef redeclarable_base::redecl_range redecl_range; typedef redeclarable_base::redecl_iterator 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; /// \brief 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(VarDeclBits.TSCSpec); } TLSKind getTLSKind() const; /// hasLocalStorage - 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; } /// isStaticLocal - 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(); } /// \brief Returns true if a variable has extern or __private_extern__ /// storage. bool hasExternalStorage() const { return getStorageClass() == SC_Extern || getStorageClass() == SC_PrivateExtern; } /// \brief 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(); } /// \brief Get the storage duration of this variable, per C++ [basic.stc]. StorageDuration getStorageDuration() const { return hasLocalStorage() ? SD_Automatic : getTSCSpec() ? SD_Thread : SD_Static; } /// \brief Compute the language linkage. LanguageLinkage getLanguageLinkage() const; /// \brief Determines whether this variable is a variable with /// external, C linkage. bool isExternC() const; /// \brief Determines whether this variable's context is, or is nested within, /// a C++ extern "C" linkage spec. bool isInExternCContext() const; /// \brief Determines whether this variable's context is, or is nested within, /// a C++ extern "C++" linkage spec. bool isInExternCXXContext() const; /// isLocalVarDecl - 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; } /// \brief Similar to isLocalVarDecl but also includes parameters. bool isLocalVarDeclOrParm() const { return isLocalVarDecl() || getKind() == Decl::ParmVar; } /// isFunctionOrMethodVarDecl - 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; } /// \brief 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(this)->getCanonicalDecl(); } enum DefinitionKind { DeclarationOnly, ///< This declaration is only a declaration. TentativeDefinition, ///< This declaration is a tentative definition. Definition ///< This declaration is definitely a definition. }; /// \brief 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()); } /// \brief Check whether this variable is defined in this /// translation unit. DefinitionKind hasDefinition(ASTContext &) const; DefinitionKind hasDefinition() const { return hasDefinition(getASTContext()); } /// \brief 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(this)->getActingDefinition(); } /// \brief Get the real (not just tentative) definition for this declaration. VarDecl *getDefinition(ASTContext &); const VarDecl *getDefinition(ASTContext &C) const { return const_cast(this)->getDefinition(C); } VarDecl *getDefinition() { return getDefinition(getASTContext()); } const VarDecl *getDefinition() const { return const_cast(this)->getDefinition(); } /// \brief Determine whether this is or was instantiated from an out-of-line /// definition of a static data member. bool isOutOfLine() const override; /// isFileVarDecl - 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; } /// getAnyInitializer - Get the initializer for this variable, no matter which /// declaration it is attached to. const Expr *getAnyInitializer() const { const VarDecl *D; return getAnyInitializer(D); } /// getAnyInitializer - 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(this)->getInit(); } Expr *getInit(); /// \brief Retrieve the address of the initializer expression. Stmt **getInitAddress(); void setInit(Expr *I); /// \brief 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; /// \brief 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 &Notes) const; /// \brief 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; /// \brief Determines whether it is already known whether the /// initializer is an integral constant expression or not. bool isInitKnownICE() const; /// \brief 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; /// \brief 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; } /// \brief 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(VarDeclBits.InitStyle); } /// \brief Whether the initializer is a direct-initializer (list or call). bool isDirectInit() const { return getInitStyle() != CInit; } /// \brief If this definition should pretend to be a declaration. bool isThisDeclarationADemotedDefinition() const { return isa(this) ? false : NonParmVarDeclBits.IsThisDeclarationADemotedDefinition; } /// \brief 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(this) && "Cannot demote ParmVarDecls!"); NonParmVarDeclBits.IsThisDeclarationADemotedDefinition = 1; } /// \brief Determine whether this variable is the exception variable in a /// C++ catch statememt or an Objective-C \@catch statement. bool isExceptionVariable() const { return isa(this) ? false : NonParmVarDeclBits.ExceptionVar; } void setExceptionVariable(bool EV) { assert(!isa(this)); NonParmVarDeclBits.ExceptionVar = EV; } /// \brief 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(this) ? false : NonParmVarDeclBits.NRVOVariable; } void setNRVOVariable(bool NRVO) { assert(!isa(this)); NonParmVarDeclBits.NRVOVariable = NRVO; } /// \brief Determine whether this variable is the for-range-declaration in /// a C++0x for-range statement. bool isCXXForRangeDecl() const { return isa(this) ? false : NonParmVarDeclBits.CXXForRangeDecl; } void setCXXForRangeDecl(bool FRD) { assert(!isa(this)); NonParmVarDeclBits.CXXForRangeDecl = FRD; } /// \brief 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. bool isARCPseudoStrong() const { return isa(this) ? false : NonParmVarDeclBits.ARCPseudoStrong; } void setARCPseudoStrong(bool ps) { assert(!isa(this)); NonParmVarDeclBits.ARCPseudoStrong = ps; } /// Whether this variable is (C++1z) inline. bool isInline() const { return isa(this) ? false : NonParmVarDeclBits.IsInline; } bool isInlineSpecified() const { return isa(this) ? false : NonParmVarDeclBits.IsInlineSpecified; } void setInlineSpecified() { assert(!isa(this)); NonParmVarDeclBits.IsInline = true; NonParmVarDeclBits.IsInlineSpecified = true; } void setImplicitlyInline() { assert(!isa(this)); NonParmVarDeclBits.IsInline = true; } /// Whether this variable is (C++11) constexpr. bool isConstexpr() const { return isa(this) ? false : NonParmVarDeclBits.IsConstexpr; } void setConstexpr(bool IC) { assert(!isa(this)); NonParmVarDeclBits.IsConstexpr = IC; } /// Whether this variable is the implicit variable for a lambda init-capture. bool isInitCapture() const { return isa(this) ? false : NonParmVarDeclBits.IsInitCapture; } void setInitCapture(bool IC) { assert(!isa(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(this) ? false : NonParmVarDeclBits.PreviousDeclInSameBlockScope; } void setPreviousDeclInSameBlockScope(bool Same) { assert(!isa(this)); NonParmVarDeclBits.PreviousDeclInSameBlockScope = Same; } /// \brief Retrieve the variable declaration from which this variable could /// be instantiated, if it is an instantiation (rather than a non-template). VarDecl *getTemplateInstantiationPattern() const; /// \brief 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; /// \brief 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; /// \brief 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; /// \brief If this variable is an instantiation of a static data member of a /// class template specialization, retrieves the member specialization /// information. MemberSpecializationInfo *getMemberSpecializationInfo() const; /// \brief 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()); /// \brief Specify that this variable is an instantiation of the /// static data member VD. void setInstantiationOfStaticDataMember(VarDecl *VD, TemplateSpecializationKind TSK); /// \brief 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); // 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: static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType T); static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType Type) : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, /*tinfo*/ nullptr, SC_None) { setImplicit(); } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ImplicitParam; } }; /// ParmVarDecl - 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(this)->getDefaultArg(); } void setDefaultArg(Expr *defarg); /// \brief 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(this)->getUninstantiatedDefaultArg(); } /// hasDefaultArg - Determines whether this parameter has a default argument, /// either parsed or not. bool hasDefaultArg() const; /// hasUnparsedDefaultArg - 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; } /// setUnparsedDefaultArg - 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; /// \brief Determine whether this parameter is actually a function /// parameter pack. bool isParameterPack() const; /// setOwningFunction - 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; }; /// FunctionDecl - An instance of this class is created to represent 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 { public: /// \brief The kind of templated function a FunctionDecl can be. enum TemplatedKind { TK_NonTemplate, TK_FunctionTemplate, TK_MemberSpecialization, TK_FunctionTemplateSpecialization, TK_DependentFunctionTemplateSpecialization }; private: /// ParamInfo - 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; LazyDeclStmtPtr Body; // FIXME: This can be packed into the bitfields in DeclContext. // NOTE: VC++ packs bitfields poorly if the types differ. unsigned SClass : 3; unsigned IsInline : 1; unsigned IsInlineSpecified : 1; protected: // This is shared by CXXConstructorDecl, CXXConversionDecl, and // CXXDeductionGuideDecl. unsigned IsExplicitSpecified : 1; private: unsigned IsVirtualAsWritten : 1; unsigned IsPure : 1; unsigned HasInheritedPrototype : 1; unsigned HasWrittenPrototype : 1; unsigned IsDeleted : 1; unsigned IsTrivial : 1; // sunk from CXXMethodDecl unsigned IsDefaulted : 1; // sunk from CXXMethoDecl unsigned IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl unsigned HasImplicitReturnZero : 1; unsigned IsLateTemplateParsed : 1; unsigned IsConstexpr : 1; /// \brief Indicates if the function uses __try. unsigned UsesSEHTry : 1; /// \brief Indicates if the function was a definition but its body was /// skipped. unsigned HasSkippedBody : 1; /// Indicates if the function declaration will have a body, once we're done /// parsing it. (We don't set it to false when we're done parsing, in the /// hopes this is simpler.) unsigned WillHaveBody : 1; /// \brief 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; /// \brief 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 TemplateOrSpecialization; /// DNLoc - Provides source/type location info for the /// declaration name embedded in the DeclaratorDecl base class. DeclarationNameLoc DNLoc; /// \brief 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); /// \brief 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 NewParamInfo); protected: FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified, bool isConstexprSpecified) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), DeclContext(DK), redeclarable_base(C), ParamInfo(nullptr), Body(), SClass(S), IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), IsExplicitSpecified(false), IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), IsDefaulted(false), IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false), EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), DNLoc(NameInfo.getInfo()) {} typedef Redeclarable redeclarable_base; FunctionDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } FunctionDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } FunctionDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } public: typedef redeclarable_base::redecl_range redecl_range; typedef redeclarable_base::redecl_iterator 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; /// \brief Returns true if the function has a body (definition). 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); } /// hasTrivialBody - Returns whether the function has a trivial body that does /// not require any specific codegen. bool hasTrivialBody() const; /// isDefined - Returns true if the function is defined at all, including /// a deleted definition. Except for the behavior when the function is /// deleted, behaves like hasBody. bool isDefined(const FunctionDecl *&Definition) const; virtual bool isDefined() const { const FunctionDecl* Definition; return isDefined(Definition); } /// \brief Get the definition for this declaration. FunctionDecl *getDefinition() { const FunctionDecl *Definition; if (isDefined(Definition)) return const_cast(Definition); return nullptr; } const FunctionDecl *getDefinition() const { return const_cast(this)->getDefinition(); } /// getBody - 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); } /// isThisDeclarationADefinition - Returns whether this specific /// declaration of the function is also a definition. This does not /// determine whether the function has been defined (e.g., in a /// previous definition); for that information, use isDefined. Note /// that this returns false for a defaulted function unless that function /// has been implicitly defined (possibly as deleted). bool isThisDeclarationADefinition() const { return IsDeleted || Body || IsLateTemplateParsed; } /// doesThisDeclarationHaveABody - Returns whether this specific /// declaration of the function has a body - that is, if it is a non- /// deleted definition. 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 IsVirtualAsWritten; } void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; } /// Whether this virtual function is pure, i.e. makes the containing class /// abstract. bool isPure() const { return IsPure; } void setPure(bool P = true); /// Whether this templated function will be late parsed. bool isLateTemplateParsed() const { return IsLateTemplateParsed; } void setLateTemplateParsed(bool ILT = true) { 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 IsTrivial; } void setTrivial(bool IT) { IsTrivial = IT; } /// Whether this function is defaulted per C++0x. Only valid for /// special member functions. bool isDefaulted() const { return IsDefaulted; } void setDefaulted(bool D = true) { IsDefaulted = D; } /// Whether this function is explicitly defaulted per C++0x. Only valid /// for special member functions. bool isExplicitlyDefaulted() const { return IsExplicitlyDefaulted; } void setExplicitlyDefaulted(bool ED = true) { 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 HasImplicitReturnZero; } void setHasImplicitReturnZero(bool IRZ) { HasImplicitReturnZero = IRZ; } /// \brief 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; } bool hasWrittenPrototype() const { return HasWrittenPrototype; } /// \brief Whether this function inherited its prototype from a /// previous declaration. bool hasInheritedPrototype() const { return HasInheritedPrototype; } void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; } /// Whether this is a (C++11) constexpr function or constexpr constructor. bool isConstexpr() const { return IsConstexpr; } void setConstexpr(bool IC) { IsConstexpr = IC; } /// \brief Indicates the function uses __try. bool usesSEHTry() const { return UsesSEHTry; } void setUsesSEHTry(bool UST) { UsesSEHTry = UST; } /// \brief 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()->IsDeleted; } bool isDeletedAsWritten() const { return IsDeleted && !IsDefaulted; } void setDeletedAsWritten(bool D = true) { IsDeleted = D; } /// \brief Determines whether this function is "main", which is the /// entry point into an executable program. bool isMain() const; /// \brief Determines whether this function is a MSVCRT user defined entry /// point. bool isMSVCRTEntryPoint() const; /// \brief 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; /// \brief 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. [...] bool isReplaceableGlobalAllocationFunction() const; /// Compute the language linkage. LanguageLinkage getLanguageLinkage() const; /// \brief Determines whether this function is a function with /// external, C linkage. bool isExternC() const; /// \brief Determines whether this function's context is, or is nested within, /// a C++ extern "C" linkage spec. bool isInExternCContext() const; /// \brief Determines whether this function's context is, or is nested within, /// a C++ extern "C++" linkage spec. bool isInExternCXXContext() const; /// \brief Determines whether this is a global function. bool isGlobal() const; /// \brief Determines whether this function is known to be 'noreturn', through /// an attribute on its declaration or its type. bool isNoReturn() const; /// \brief True if the function was a definition but its body was skipped. bool hasSkippedBody() const { return HasSkippedBody; } void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; } /// True if this function will eventually have a body, once it's fully parsed. bool willHaveBody() const { return WillHaveBody; } void setWillHaveBody(bool V = true) { WillHaveBody = V; } void setPreviousDeclaration(FunctionDecl * PrevDecl); FunctionDecl *getCanonicalDecl() override; const FunctionDecl *getCanonicalDecl() const { return const_cast(this)->getCanonicalDecl(); } unsigned getBuiltinID() const; // ArrayRef interface to parameters. ArrayRef parameters() const { return {ParamInfo, getNumParams()}; } MutableArrayRef parameters() { return {ParamInfo, getNumParams()}; } // Iterator access to formal parameters. typedef MutableArrayRef::iterator param_iterator; typedef ArrayRef::const_iterator param_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(); } /// getNumParams - 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 NewParamInfo) { setParams(getASTContext(), NewParamInfo); } /// getMinRequiredArguments - 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 { assert(getType()->getAs() && "Expected a FunctionType!"); return getType()->getAs()->getReturnType(); } /// \brief 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; /// \brief Attempt to compute an informative source range covering the /// function exception specification, if any. SourceRange getExceptionSpecSourceRange() const; /// \brief Determine the type of an expression that calls this function. QualType getCallResultType() const { assert(getType()->getAs() && "Expected a FunctionType!"); return getType()->getAs()->getCallResultType(getASTContext()); } /// \brief Returns the WarnUnusedResultAttr that is either declared on this /// function, or its return type declaration. const Attr *getUnusedResultAttr() const; /// \brief Returns true if this function or its return type has the /// warn_unused_result attribute. bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; } /// \brief Returns the storage class as written in the source. For the /// computed linkage of symbol, see getLinkage. StorageClass getStorageClass() const { return StorageClass(SClass); } /// \brief Determine whether the "inline" keyword was specified for this /// function. bool isInlineSpecified() const { return IsInlineSpecified; } /// Set whether the "inline" keyword was specified for this function. void setInlineSpecified(bool I) { IsInlineSpecified = I; IsInline = I; } /// Flag that this function is implicitly inline. void setImplicitlyInline() { IsInline = true; } /// \brief 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 IsInline; } bool isInlineDefinitionExternallyVisible() const; bool isMSExternInline() const; bool doesDeclarationForceExternallyVisibleDefinition() const; /// isOverloadedOperator - 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; /// \brief 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 /// struct X { /// void f(T); /// }; /// \endcode /// /// The declaration for X::f is a (non-templated) FunctionDecl /// whose parent is the class template specialization X. For /// this declaration, getInstantiatedFromFunction() will return /// the FunctionDecl X::A. When a complete definition of /// X::A is required, it will be instantiated from the /// declaration returned by getInstantiatedFromMemberFunction(). FunctionDecl *getInstantiatedFromMemberFunction() const; /// \brief What kind of templated function this is. TemplatedKind getTemplatedKind() const; /// \brief If this function is an instantiation of a member function of a /// class template specialization, retrieves the member specialization /// information. MemberSpecializationInfo *getMemberSpecializationInfo() const; /// \brief Specify that this record is an instantiation of the /// member function FD. void setInstantiationOfMemberFunction(FunctionDecl *FD, TemplateSpecializationKind TSK) { setInstantiationOfMemberFunction(getASTContext(), FD, TSK); } /// \brief 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); /// \brief Determine whether this function is a function template /// specialization. bool isFunctionTemplateSpecialization() const { return getPrimaryTemplate() != nullptr; } /// \brief Retrieve the class scope template pattern that this function /// template specialization is instantiated from. FunctionDecl *getClassScopeSpecializationPattern() const; /// \brief If this function is actually a function template specialization, /// retrieve information about this function template specialization. /// Otherwise, returns NULL. FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const; /// \brief 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; /// \brief Determines if the given function was instantiated from a /// function template. bool isTemplateInstantiation() const; /// \brief 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; /// \brief 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; /// \brief 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; /// \brief 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; /// \brief 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); } /// \brief 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; /// \brief Determine what kind of template instantiation this function /// represents. TemplateSpecializationKind getTemplateSpecializationKind() const; /// \brief Determine what kind of template instantiation this function /// represents. void setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation = SourceLocation()); /// \brief 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; /// \brief Determine whether this is or was instantiated from an out-of-line /// definition of a member function. bool isOutOfLine() const override; /// \brief 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; // 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(const_cast(D)); } static FunctionDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } friend class ASTDeclReader; friend class ASTDeclWriter; }; /// FieldDecl - An instance of this class is created by Sema::ActOnField to /// represent a member of a struct/union/class. class FieldDecl : public DeclaratorDecl, public Mergeable { // FIXME: This can be packed into the bitfields in Decl. unsigned Mutable : 1; mutable unsigned CachedFieldIndex : 31; /// 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_BitWidthOrNothing = (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, }; /// \brief Storage for either the bit-width, the in-class /// initializer, or the captured variable length array bound. /// /// We can safely combine these because in-class initializers are /// not permitted for bit-fields, and both are exclusive with VLA /// captures. /// /// If the storage kind is ISK_InClassCopyInit or /// ISK_InClassListInit, but the initializer is null, then this /// field has an in-class initializer which has not yet been parsed /// and attached. llvm::PointerIntPair 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), Mutable(Mutable), CachedFieldIndex(0), InitStorage(BW, (InitStorageKind) InitStyle) { assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); } public: 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); /// getFieldIndex - Returns the index of this field within its record, /// as appropriate for passing to ASTRecordLayout::getFieldOffset. unsigned getFieldIndex() const; /// isMutable - Determines whether this field is mutable (C++ only). bool isMutable() const { return Mutable; } /// \brief Determines whether this field is a bitfield. bool isBitField() const { return InitStorage.getInt() == ISK_BitWidthOrNothing && InitStorage.getPointer() != nullptr; } /// @brief Determines whether this is an unnamed bitfield. bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); } /// isAnonymousStructOrUnion - 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 { return isBitField() ? static_cast(InitStorage.getPointer()) : nullptr; } unsigned getBitWidthValue(const ASTContext &Ctx) const; /// setBitWidth - Set the bit-field width for this member. // Note: used by some clients (i.e., do not remove it). void setBitWidth(Expr *Width) { assert(InitStorage.getInt() == ISK_BitWidthOrNothing && InitStorage.getPointer() == nullptr && "bit width, initializer or captured type already set"); InitStorage.setPointerAndInt(Width, ISK_BitWidthOrNothing); } /// removeBitWidth - 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.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); } /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which /// this field has. InClassInitStyle getInClassInitStyle() const { InitStorageKind storageKind = InitStorage.getInt(); return (storageKind == ISK_CapturedVLAType ? ICIS_NoInit : (InClassInitStyle) storageKind); } /// hasInClassInitializer - Determine whether this member has a C++11 in-class /// initializer. bool hasInClassInitializer() const { return getInClassInitStyle() != ICIS_NoInit; } /// getInClassInitializer - Get the C++11 in-class initializer for this /// member, or null if one has not been set. If a valid declaration has an /// in-class initializer, but this returns null, then we have not parsed and /// attached it yet. Expr *getInClassInitializer() const { return hasInClassInitializer() ? static_cast(InitStorage.getPointer()) : nullptr; } /// setInClassInitializer - Set the C++11 in-class initializer for this /// member. void setInClassInitializer(Expr *Init) { assert(hasInClassInitializer() && InitStorage.getPointer() == nullptr && "bit width, initializer or captured type already set"); InitStorage.setPointer(Init); } /// removeInClassInitializer - Remove the C++11 in-class initializer from this /// member. void removeInClassInitializer() { assert(hasInClassInitializer() && "no initializer to remove"); InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); } /// \brief Determine whether this member captures the variable length array /// type. bool hasCapturedVLAType() const { return InitStorage.getInt() == ISK_CapturedVLAType; } /// \brief Get the captured variable length array type. const VariableArrayType *getCapturedVLAType() const { return hasCapturedVLAType() ? static_cast( InitStorage.getPointer()) : nullptr; } /// \brief Set the captured variable length array type for this field. void setCapturedVLAType(const VariableArrayType *VLAType); /// getParent - Returns the parent of this field declaration, which /// is the struct in which this field is defined. const RecordDecl *getParent() const { return cast(getDeclContext()); } RecordDecl *getParent() { return cast(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; } friend class ASTDeclReader; friend class ASTDeclWriter; }; /// EnumConstantDecl - 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 { 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: 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; } friend class StmtIteratorBase; }; /// IndirectFieldDecl - An instance of this class is created to represent a /// field injected from an anonymous union/struct into the parent scope. /// IndirectFieldDecl are always implicit. class IndirectFieldDecl : public ValueDecl, public Mergeable { void anchor() override; NamedDecl **Chaining; unsigned ChainingSize; IndirectFieldDecl(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, MutableArrayRef CH); public: static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, llvm::MutableArrayRef CH); static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); typedef ArrayRef::const_iterator chain_iterator; ArrayRef 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(chain().back()); } VarDecl *getVarDecl() const { assert(chain().size() >= 2); return dyn_cast(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; } friend class ASTDeclReader; }; /// TypeDecl - Represents a declaration of a type. /// class TypeDecl : public NamedDecl { void anchor() override; /// TypeForDecl - 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; /// LocStart - The start of the source range for this declaration. SourceLocation LocStart; friend class ASTContext; protected: TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation StartL = SourceLocation()) : NamedDecl(DK, DC, L, Id), TypeForDecl(nullptr), 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 getLocStart() 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 { void anchor() override; typedef std::pair ModedTInfo; llvm::PointerUnion MaybeModedTInfo; // FIXME: This can be packed into the bitfields in Decl. /// If 0, we have not computed IsTransparentTag. /// Otherwise, IsTransparentTag is (CacheIsTransparentTag >> 1). mutable unsigned CacheIsTransparentTag : 2; 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), CacheIsTransparentTag(0) {} typedef Redeclarable redeclarable_base; TypedefNameDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } TypedefNameDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } TypedefNameDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } public: typedef redeclarable_base::redecl_range redecl_range; typedef redeclarable_base::redecl_iterator 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.is(); } TypeSourceInfo *getTypeSourceInfo() const { return isModed() ? MaybeModedTInfo.get()->first : MaybeModedTInfo.get(); } QualType getUnderlyingType() const { return isModed() ? MaybeModedTInfo.get()->second : MaybeModedTInfo.get()->getType(); } void setTypeSourceInfo(TypeSourceInfo *newType) { MaybeModedTInfo = newType; } void setModedTypeSourceInfo(TypeSourceInfo *unmodedTSI, QualType modedTy) { MaybeModedTInfo = new (getASTContext()) 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 (CacheIsTransparentTag) return CacheIsTransparentTag & 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; }; /// TypedefDecl - 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; } }; /// TypeAliasDecl - Represents the declaration of a typedef-name via a C++0x /// 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; } }; /// TagDecl - Represents the declaration of a struct/union/class/enum. class TagDecl : public TypeDecl, public DeclContext, public Redeclarable { public: // This is really ugly. typedef TagTypeKind TagKind; private: // FIXME: This can be packed into the bitfields in Decl. /// TagDeclKind - The TagKind enum. unsigned TagDeclKind : 3; /// IsCompleteDefinition - True if this is a definition ("struct foo /// {};"), false if it is a declaration ("struct foo;"). It is not /// a definition until the definition has been fully processed. unsigned IsCompleteDefinition : 1; protected: /// IsBeingDefined - True if this is currently being defined. unsigned IsBeingDefined : 1; private: /// IsEmbeddedInDeclarator - True if this tag declaration is /// "embedded" (i.e., defined or declared for the very first time) /// in the syntax of a declarator. unsigned IsEmbeddedInDeclarator : 1; /// \brief True if this tag is free standing, e.g. "struct foo;". unsigned IsFreeStanding : 1; protected: // These are used by (and only defined for) EnumDecl. unsigned NumPositiveBits : 8; unsigned NumNegativeBits : 8; /// IsScoped - True if this tag declaration is a scoped enumeration. Only /// possible in C++11 mode. unsigned IsScoped : 1; /// IsScopedUsingClassTag - 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. unsigned IsScopedUsingClassTag : 1; /// IsFixed - True if this is an enumeration with fixed underlying type. Only /// possible in C++11, Microsoft extensions, or Objective C mode. unsigned IsFixed : 1; /// \brief 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. unsigned MayHaveOutOfDateDef : 1; /// Has the full definition of this type been required by a use somewhere in /// the TU. unsigned IsCompleteDefinitionRequired : 1; private: SourceRange BraceRange; // A struct representing syntactic qualifier info, // to be used for the (uncommon) case of out-of-line declarations. typedef QualifierInfo ExtInfo; /// \brief 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 TypedefNameDeclOrQualifier; bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is(); } ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get(); } const ExtInfo *getExtInfo() const { return TypedefNameDeclOrQualifier.get(); } protected: TagDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, TagDecl *PrevDecl, SourceLocation StartL) : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), redeclarable_base(C), TagDeclKind(TK), IsCompleteDefinition(false), IsBeingDefined(false), IsEmbeddedInDeclarator(false), IsFreeStanding(false), IsCompleteDefinitionRequired(false), TypedefNameDeclOrQualifier((TypedefNameDecl *)nullptr) { assert((DK != Enum || TK == TTK_Enum) && "EnumDecl not matched with TTK_Enum"); setPreviousDecl(PrevDecl); } typedef Redeclarable redeclarable_base; TagDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); } TagDecl *getPreviousDeclImpl() override { return getPreviousDecl(); } TagDecl *getMostRecentDeclImpl() override { return getMostRecentDecl(); } /// @brief Completes the definition of this tag declaration. /// /// This is a helper function for derived classes. void completeDefinition(); public: typedef redeclarable_base::redecl_range redecl_range; typedef redeclarable_base::redecl_iterator 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; } /// getInnerLocStart - Return SourceLocation representing start of source /// range ignoring outer template declarations. SourceLocation getInnerLocStart() const { return getLocStart(); } /// getOuterLocStart - 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(this)->getCanonicalDecl(); } /// isThisDeclarationADefinition() - Return true if this declaration /// is a completion definition of the type. Provided for consistency. bool isThisDeclarationADefinition() const { return isCompleteDefinition(); } /// isCompleteDefinition - Return true if this decl has its body /// fully specified. bool isCompleteDefinition() const { return IsCompleteDefinition; } /// \brief Return true if this complete decl is /// required to be complete for some existing use. bool isCompleteDefinitionRequired() const { return IsCompleteDefinitionRequired; } /// isBeingDefined - Return true if this decl is currently being defined. bool isBeingDefined() const { return IsBeingDefined; } bool isEmbeddedInDeclarator() const { return IsEmbeddedInDeclarator; } void setEmbeddedInDeclarator(bool isInDeclarator) { IsEmbeddedInDeclarator = isInDeclarator; } bool isFreeStanding() const { return IsFreeStanding; } void setFreeStanding(bool isFreeStanding = true) { IsFreeStanding = isFreeStanding; } /// \brief Whether this declaration declares a type that is /// dependent, i.e., a type that somehow depends on template /// parameters. bool isDependentType() const { return isDependentContext(); } /// @brief 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(); /// getDefinition - 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; void setCompleteDefinition(bool V) { IsCompleteDefinition = V; } void setCompleteDefinitionRequired(bool V = true) { IsCompleteDefinitionRequired = V; } StringRef getKindName() const { return TypeWithKeyword::getTagTypeKindName(getTagKind()); } TagKind getTagKind() const { return TagKind(TagDeclKind); } void setTagKind(TagKind TK) { 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(); } void setTypedefNameForAnonDecl(TypedefNameDecl *TDD); /// \brief 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; } /// \brief 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 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(const_cast(D)); } static TagDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } friend class ASTDeclReader; friend class ASTDeclWriter; }; /// EnumDecl - 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 { void anchor() override; /// IntegerType - 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 IntegerType; /// PromotionType - 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; /// \brief If this enumeration is an instantiation of a member enumeration /// of a class template specialization, this is the member specialization /// information. MemberSpecializationInfo *SpecializationInfo; EnumDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, bool Scoped, bool ScopedUsingClassTag, bool Fixed) : TagDecl(Enum, TTK_Enum, C, DC, IdLoc, Id, PrevDecl, StartLoc), SpecializationInfo(nullptr) { assert(Scoped || !ScopedUsingClassTag); IntegerType = (const Type *)nullptr; NumNegativeBits = 0; NumPositiveBits = 0; IsScoped = Scoped; IsScopedUsingClassTag = ScopedUsingClassTag; IsFixed = Fixed; } void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, TemplateSpecializationKind TSK); public: EnumDecl *getCanonicalDecl() override { return cast(TagDecl::getCanonicalDecl()); } const EnumDecl *getCanonicalDecl() const { return const_cast(this)->getCanonicalDecl(); } EnumDecl *getPreviousDecl() { return cast_or_null( static_cast(this)->getPreviousDecl()); } const EnumDecl *getPreviousDecl() const { return const_cast(this)->getPreviousDecl(); } EnumDecl *getMostRecentDecl() { return cast(static_cast(this)->getMostRecentDecl()); } const EnumDecl *getMostRecentDecl() const { return const_cast(this)->getMostRecentDecl(); } EnumDecl *getDefinition() const { return cast_or_null(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); /// completeDefinition - When created, the EnumDecl corresponds to a /// forward-declared enum. This method is used to mark the /// declaration as being defined; it's 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); // enumerator_iterator - Iterates through the enumerators of this // enumeration. typedef specific_decl_iterator enumerator_iterator; typedef llvm::iterator_range> enumerator_range; 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()); } /// getPromotionType - Return the integer type that enumerators /// should promote to. QualType getPromotionType() const { return PromotionType; } /// \brief Set the promotion type. void setPromotionType(QualType T) { PromotionType = T; } /// getIntegerType - 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()) return QualType(T, 0); return IntegerType.get()->getType().getUnqualifiedType(); } /// \brief Set the underlying integer type. void setIntegerType(QualType T) { IntegerType = T.getTypePtrOrNull(); } /// \brief Set the underlying integer type source info. void setIntegerTypeSourceInfo(TypeSourceInfo *TInfo) { IntegerType = TInfo; } /// \brief 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(); } /// \brief Retrieve the source range that covers the underlying type if /// specified. SourceRange getIntegerTypeRange() const LLVM_READONLY; /// \brief Returns the width in bits required to store all the /// non-negative enumerators of this enum. unsigned getNumPositiveBits() const { return NumPositiveBits; } void setNumPositiveBits(unsigned Num) { NumPositiveBits = Num; assert(NumPositiveBits == Num && "can't store this bitcount"); } /// \brief 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 NumNegativeBits; } void setNumNegativeBits(unsigned Num) { NumNegativeBits = Num; } /// \brief Returns true if this is a C++11 scoped enumeration. bool isScoped() const { return IsScoped; } /// \brief Returns true if this is a C++11 scoped enumeration. bool isScopedUsingClassTag() const { return IsScopedUsingClassTag; } /// \brief Returns true if this is an Objective-C, C++11, or /// Microsoft-style enumeration with a fixed underlying type. bool isFixed() const { return IsFixed; } /// \brief Returns true if this can be considered a complete type. bool isComplete() const { return isCompleteDefinition() || isFixed(); } /// 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; /// \brief Retrieve the enum definition from which this enumeration could /// be instantiated, if it is an instantiation (rather than a non-template). EnumDecl *getTemplateInstantiationPattern() const; /// \brief 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; /// \brief 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; /// \brief 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()); /// \brief 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; } /// \brief 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; } friend class ASTDeclReader; }; /// RecordDecl - 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 { // FIXME: This can be packed into the bitfields in Decl. /// HasFlexibleArrayMember - This is true if this struct ends with a flexible /// array member (e.g. int X[]) or if this union contains a struct that does. /// If so, this cannot be contained in arrays or other structs as a member. bool HasFlexibleArrayMember : 1; /// AnonymousStructOrUnion - Whether this is the type of an anonymous struct /// or union. bool AnonymousStructOrUnion : 1; /// HasObjectMember - This is true if this struct has at least one member /// containing an Objective-C object pointer type. bool HasObjectMember : 1; /// HasVolatileMember - This is true if struct has at least one member of /// 'volatile' type. bool HasVolatileMember : 1; /// \brief Whether the field declarations of this record have been loaded /// from external storage. To avoid unnecessary deserialization of /// methods/nested types we allow deserialization of just the fields /// when needed. mutable bool LoadedFieldsFromExternalStorage : 1; friend class DeclContext; 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( static_cast(this)->getPreviousDecl()); } const RecordDecl *getPreviousDecl() const { return const_cast(this)->getPreviousDecl(); } RecordDecl *getMostRecentDecl() { return cast(static_cast(this)->getMostRecentDecl()); } const RecordDecl *getMostRecentDecl() const { return const_cast(this)->getMostRecentDecl(); } bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; } void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; } /// isAnonymousStructOrUnion - 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 AnonymousStructOrUnion; } void setAnonymousStructOrUnion(bool Anon) { AnonymousStructOrUnion = Anon; } bool hasObjectMember() const { return HasObjectMember; } void setHasObjectMember (bool val) { HasObjectMember = val; } bool hasVolatileMember() const { return HasVolatileMember; } void setHasVolatileMember (bool val) { HasVolatileMember = val; } bool hasLoadedFieldsFromExternalStorage() const { return LoadedFieldsFromExternalStorage; } void setHasLoadedFieldsFromExternalStorage(bool val) { LoadedFieldsFromExternalStorage = val; } /// \brief 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; /// \brief Determine whether this record is a class describing a lambda /// function object. bool isLambda() const; /// \brief Determine whether this record is a record for captured variables in /// CapturedStmt construct. bool isCapturedRecord() const; /// \brief Mark the record as a record for captured variables in CapturedStmt /// construct. void setCapturedRecord(); /// getDefinition - 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(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. typedef specific_decl_iterator field_iterator; typedef llvm::iterator_range> field_range; 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()); } // field_empty - Whether there are any fields (non-static data // members) in this record. bool field_empty() const { return field_begin() == field_end(); } /// completeDefinition - Notes 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; } /// isMsStrust - 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; /// \brief 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: /// \brief Deserialize just the fields. void LoadFieldsFromExternalStorage() const; }; class FileScopeAsmDecl : public Decl { virtual void anchor(); StringLiteral *AsmString; SourceLocation RParenLoc; FileScopeAsmDecl(DeclContext *DC, StringLiteral *asmstring, SourceLocation StartL, SourceLocation EndL) : Decl(FileScopeAsm, DC, StartL), AsmString(asmstring), RParenLoc(EndL) {} 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; } }; /// BlockDecl - This 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 { 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 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; } /// 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: // FIXME: This can be packed into the bitfields in Decl. bool IsVariadic : 1; bool CapturesCXXThis : 1; bool BlockMissingReturnType : 1; bool IsConversionFromLambda : 1; /// ParamInfo - 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; unsigned NumParams; Stmt *Body; TypeSourceInfo *SignatureAsWritten; const Capture *Captures; unsigned NumCaptures; unsigned ManglingNumber; Decl *ManglingContextDecl; protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) : Decl(Block, DC, CaretLoc), DeclContext(Block), IsVariadic(false), CapturesCXXThis(false), BlockMissingReturnType(true), IsConversionFromLambda(false), ParamInfo(nullptr), NumParams(0), Body(nullptr), SignatureAsWritten(nullptr), Captures(nullptr), NumCaptures(0), ManglingNumber(0), ManglingContextDecl(nullptr) {} 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 IsVariadic; } void setIsVariadic(bool value) { 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 parameters() const { return {ParamInfo, getNumParams()}; } MutableArrayRef parameters() { return {ParamInfo, getNumParams()}; } // Iterator access to formal parameters. typedef MutableArrayRef::iterator param_iterator; typedef ArrayRef::const_iterator param_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 NewParamInfo); /// hasCaptures - True if this block (or its nested blocks) captures /// anything of local storage from its enclosing scopes. bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; } /// getNumCaptures - Returns the number of captured variables. /// Does not include an entry for 'this'. unsigned getNumCaptures() const { return NumCaptures; } typedef ArrayRef::const_iterator capture_const_iterator; ArrayRef 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 CapturesCXXThis; } bool blockMissingReturnType() const { return BlockMissingReturnType; } void setBlockMissingReturnType(bool val) { BlockMissingReturnType = val; } bool isConversionFromLambda() const { return IsConversionFromLambda; } void setIsConversionFromLambda(bool val) { IsConversionFromLambda = val; } bool capturesVariable(const VarDecl *var) const; void setCaptures(ASTContext &Context, ArrayRef 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(const_cast(D)); } static BlockDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } }; /// \brief This represents the body of a CapturedStmt, and serves as its /// DeclContext. class CapturedDecl final : public Decl, public DeclContext, private llvm::TrailingObjects { protected: size_t numTrailingObjects(OverloadToken) { return NumParams; } private: /// \brief The number of parameters to the outlined function. unsigned NumParams; /// \brief The position of context parameter in list of parameters. unsigned ContextParam; /// \brief The body of the outlined function. llvm::PointerIntPair BodyAndNothrow; explicit CapturedDecl(DeclContext *DC, unsigned NumParams); ImplicitParamDecl *const *getParams() const { return getTrailingObjects(); } ImplicitParamDecl **getParams() { return getTrailingObjects(); } public: 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 parameters() const { return {getParams(), getNumParams()}; } MutableArrayRef parameters() { return {getParams(), getNumParams()}; } /// \brief 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; } typedef ImplicitParamDecl *const *param_iterator; typedef llvm::iterator_range param_range; /// \brief Retrieve an iterator pointing to the first parameter decl. param_iterator param_begin() const { return getParams(); } /// \brief 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(const_cast(D)); } static CapturedDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } friend class ASTDeclReader; friend class ASTDeclWriter; friend TrailingObjects; }; /// \brief 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 { /// \brief 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 ImportedAndComplete; /// \brief The next import in the list of imports local to the translation /// unit being parsed (not loaded from an AST file). ImportDecl *NextLocalImport; friend class ASTReader; friend class ASTDeclReader; friend class ASTContext; friend TrailingObjects; ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, ArrayRef IdentifierLocs); ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, SourceLocation EndLoc); ImportDecl(EmptyShell Empty) : Decl(Import, Empty), NextLocalImport() { } public: /// \brief Create a new module import declaration. static ImportDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, Module *Imported, ArrayRef IdentifierLocs); /// \brief Create a new module import declaration for an implicitly-generated /// import. static ImportDecl *CreateImplicit(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, Module *Imported, SourceLocation EndLoc); /// \brief Create a new, deserialized module import declaration. static ImportDecl *CreateDeserialized(ASTContext &C, unsigned ID, unsigned NumLocations); /// \brief Retrieve the module that was imported by the import declaration. Module *getImportedModule() const { return ImportedAndComplete.getPointer(); } /// \brief 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 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; } }; /// \brief 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: /// \brief The source location for the right brace (if valid). SourceLocation RBraceLoc; ExportDecl(DeclContext *DC, SourceLocation ExportLoc) : Decl(Export, DC, ExportLoc), DeclContext(Export), RBraceLoc(SourceLocation()) { } friend class ASTDeclReader; 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 getLocEnd() 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()->getLocEnd(); } SourceRange getSourceRange() const override LLVM_READONLY { return SourceRange(getLocation(), getLocEnd()); } 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(const_cast(D)); } static ExportDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } }; /// \brief Represents an empty-declaration. class EmptyDecl : public Decl { virtual void anchor(); EmptyDecl(DeclContext *DC, SourceLocation L) : Decl(Empty, DC, L) { } 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(ND), DiagnosticsEngine::ak_nameddecl); return DB; } inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, const NamedDecl* ND) { PD.AddTaggedVal(reinterpret_cast(ND), DiagnosticsEngine::ak_nameddecl); return PD; } template void Redeclarable::setPreviousDecl(decl_type *PrevDecl) { // Note: This routine is implemented here because we need both NamedDecl // and Redeclarable to be defined. assert(RedeclLink.NextIsLatest() && "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.NextIsLatest() && "Expected first"); decl_type *MostRecent = First->getNextRedeclaration(); RedeclLink = PreviousDeclLink(cast(MostRecent)); // If the declaration was previously visible, a redeclaration of it remains // visible even if it wouldn't be visible by itself. static_cast(this)->IdentifierNamespace |= MostRecent->getIdentifierNamespace() & (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type); } else { // Make this first. First = static_cast(this); } // First one will point to this one as latest. First->RedeclLink.setLatest(static_cast(this)); assert(!isa(static_cast(this)) || cast(static_cast(this))->isLinkageValid()); } // Inline function definitions. /// \brief 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(); } /// \brief 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(); } } // end namespace clang #endif Index: vendor/clang/dist/include/clang/AST/DeclBase.h =================================================================== --- vendor/clang/dist/include/clang/AST/DeclBase.h (revision 318415) +++ vendor/clang/dist/include/clang/AST/DeclBase.h (revision 318416) @@ -1,1947 +1,1961 @@ //===-- DeclBase.h - Base Classes for representing declarations -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the Decl and DeclContext interfaces. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_DECLBASE_H #define LLVM_CLANG_AST_DECLBASE_H #include "clang/AST/AttrIterator.h" #include "clang/AST/DeclarationName.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/VersionTuple.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PrettyStackTrace.h" namespace clang { class ASTMutationListener; class BlockDecl; class CXXRecordDecl; class CompoundStmt; class DeclContext; class DeclarationName; class DependentDiagnostic; class EnumDecl; class ExportDecl; class FunctionDecl; class FunctionType; enum Linkage : unsigned char; class LinkageComputer; class LinkageSpecDecl; class Module; class NamedDecl; class NamespaceDecl; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCContainerDecl; class ObjCImplDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; class ObjCMethodDecl; class ObjCProtocolDecl; struct PrintingPolicy; class RecordDecl; class Stmt; class StoredDeclsMap; class TemplateDecl; class TranslationUnitDecl; class UsingDirectiveDecl; } namespace clang { /// \brief Captures the result of checking the availability of a /// declaration. enum AvailabilityResult { AR_Available = 0, AR_NotYetIntroduced, AR_Deprecated, AR_Unavailable }; /// Decl - This represents one declaration (or definition), e.g. a variable, /// typedef, function, struct, etc. /// /// Note: There are objects tacked on before the *beginning* of Decl /// (and its subclasses) in its Decl::operator new(). Proper alignment /// of all subclasses (not requiring more than the alignment of Decl) is /// asserted in DeclBase.cpp. class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { public: /// \brief Lists the kind of concrete classes of Decl. enum Kind { #define DECL(DERIVED, BASE) DERIVED, #define ABSTRACT_DECL(DECL) #define DECL_RANGE(BASE, START, END) \ first##BASE = START, last##BASE = END, #define LAST_DECL_RANGE(BASE, START, END) \ first##BASE = START, last##BASE = END #include "clang/AST/DeclNodes.inc" }; /// \brief A placeholder type used to construct an empty shell of a /// decl-derived type that will be filled in later (e.g., by some /// deserialization method). struct EmptyShell { }; /// IdentifierNamespace - The different namespaces in which /// declarations may appear. According to C99 6.2.3, there are /// four namespaces, labels, tags, members and ordinary /// identifiers. C++ describes lookup completely differently: /// certain lookups merely "ignore" certain kinds of declarations, /// usually based on whether the declaration is of a type, etc. /// /// These are meant as bitmasks, so that searches in /// C++ can look into the "tag" namespace during ordinary lookup. /// /// Decl currently provides 15 bits of IDNS bits. enum IdentifierNamespace { /// Labels, declared with 'x:' and referenced with 'goto x'. IDNS_Label = 0x0001, /// Tags, declared with 'struct foo;' and referenced with /// 'struct foo'. All tags are also types. This is what /// elaborated-type-specifiers look for in C. /// This also contains names that conflict with tags in the /// same scope but that are otherwise ordinary names (non-type /// template parameters and indirect field declarations). IDNS_Tag = 0x0002, /// Types, declared with 'struct foo', typedefs, etc. /// This is what elaborated-type-specifiers look for in C++, /// but note that it's ill-formed to find a non-tag. IDNS_Type = 0x0004, /// Members, declared with object declarations within tag /// definitions. In C, these can only be found by "qualified" /// lookup in member expressions. In C++, they're found by /// normal lookup. IDNS_Member = 0x0008, /// Namespaces, declared with 'namespace foo {}'. /// Lookup for nested-name-specifiers find these. IDNS_Namespace = 0x0010, /// Ordinary names. In C, everything that's not a label, tag, /// member, or function-local extern ends up here. IDNS_Ordinary = 0x0020, /// Objective C \@protocol. IDNS_ObjCProtocol = 0x0040, /// This declaration is a friend function. A friend function /// declaration is always in this namespace but may also be in /// IDNS_Ordinary if it was previously declared. IDNS_OrdinaryFriend = 0x0080, /// This declaration is a friend class. A friend class /// declaration is always in this namespace but may also be in /// IDNS_Tag|IDNS_Type if it was previously declared. IDNS_TagFriend = 0x0100, /// This declaration is a using declaration. A using declaration /// *introduces* a number of other declarations into the current /// scope, and those declarations use the IDNS of their targets, /// but the actual using declarations go in this namespace. IDNS_Using = 0x0200, /// This declaration is a C++ operator declared in a non-class /// context. All such operators are also in IDNS_Ordinary. /// C++ lexical operator lookup looks for these. IDNS_NonMemberOperator = 0x0400, /// This declaration is a function-local extern declaration of a /// variable or function. This may also be IDNS_Ordinary if it /// has been declared outside any function. These act mostly like /// invisible friend declarations, but are also visible to unqualified /// lookup within the scope of the declaring function. IDNS_LocalExtern = 0x0800, /// This declaration is an OpenMP user defined reduction construction. IDNS_OMPReduction = 0x1000 }; /// ObjCDeclQualifier - 'Qualifiers' written next to the return and /// parameter types in method declarations. Other than remembering /// them and mangling them into the method's signature string, these /// are ignored by the compiler; they are consumed by certain /// remote-messaging frameworks. /// /// in, inout, and out are mutually exclusive and apply only to /// method parameters. bycopy and byref are mutually exclusive and /// apply only to method parameters (?). oneway applies only to /// results. All of these expect their corresponding parameter to /// have a particular type. None of this is currently enforced by /// clang. /// /// This should be kept in sync with ObjCDeclSpec::ObjCDeclQualifier. enum ObjCDeclQualifier { OBJC_TQ_None = 0x0, OBJC_TQ_In = 0x1, OBJC_TQ_Inout = 0x2, OBJC_TQ_Out = 0x4, OBJC_TQ_Bycopy = 0x8, OBJC_TQ_Byref = 0x10, OBJC_TQ_Oneway = 0x20, /// The nullability qualifier is set when the nullability of the /// result or parameter was expressed via a context-sensitive /// keyword. OBJC_TQ_CSNullability = 0x40 }; protected: // Enumeration values used in the bits stored in NextInContextAndBits. enum { /// \brief Whether this declaration is a top-level declaration (function, /// global variable, etc.) that is lexically inside an objc container /// definition. TopLevelDeclInObjCContainerFlag = 0x01, /// \brief Whether this declaration is private to the module in which it was /// defined. ModulePrivateFlag = 0x02 }; /// \brief The next declaration within the same lexical /// DeclContext. These pointers form the linked list that is /// traversed via DeclContext's decls_begin()/decls_end(). /// /// The extra two bits are used for the TopLevelDeclInObjCContainer and /// ModulePrivate bits. llvm::PointerIntPair NextInContextAndBits; private: friend class DeclContext; struct MultipleDC { DeclContext *SemanticDC; DeclContext *LexicalDC; }; /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. /// For declarations that don't contain C++ scope specifiers, it contains /// the DeclContext where the Decl was declared. /// For declarations with C++ scope specifiers, it contains a MultipleDC* /// with the context where it semantically belongs (SemanticDC) and the /// context where it was lexically declared (LexicalDC). /// e.g.: /// /// namespace A { /// void f(); // SemanticDC == LexicalDC == 'namespace A' /// } /// void A::f(); // SemanticDC == namespace 'A' /// // LexicalDC == global namespace llvm::PointerUnion DeclCtx; inline bool isInSemaDC() const { return DeclCtx.is(); } inline bool isOutOfSemaDC() const { return DeclCtx.is(); } inline MultipleDC *getMultipleDC() const { return DeclCtx.get(); } inline DeclContext *getSemanticDC() const { return DeclCtx.get(); } /// Loc - The location of this decl. SourceLocation Loc; /// DeclKind - This indicates which class this is. unsigned DeclKind : 7; /// InvalidDecl - This indicates a semantic error occurred. unsigned InvalidDecl : 1; /// HasAttrs - This indicates whether the decl has attributes or not. unsigned HasAttrs : 1; /// Implicit - Whether this declaration was implicitly generated by /// the implementation rather than explicitly written by the user. unsigned Implicit : 1; /// \brief Whether this declaration was "used", meaning that a definition is /// required. unsigned Used : 1; /// \brief Whether this declaration was "referenced". /// The difference with 'Used' is whether the reference appears in a /// evaluated context or not, e.g. functions used in uninstantiated templates /// are regarded as "referenced" but not "used". unsigned Referenced : 1; /// \brief Whether statistic collection is enabled. static bool StatisticsEnabled; protected: /// Access - Used by C++ decls for the access specifier. // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum unsigned Access : 2; friend class CXXClassMemberWrapper; /// \brief Whether this declaration was loaded from an AST file. unsigned FromASTFile : 1; /// \brief Whether this declaration is hidden from normal name lookup, e.g., /// because it is was loaded from an AST file is either module-private or /// because its submodule has not been made visible. unsigned Hidden : 1; /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. unsigned IdentifierNamespace : 13; /// \brief If 0, we have not computed the linkage of this declaration. /// Otherwise, it is the linkage + 1. mutable unsigned CacheValidAndLinkage : 3; friend class ASTDeclWriter; friend class ASTDeclReader; friend class ASTReader; friend class LinkageComputer; template friend class Redeclarable; /// \brief Allocate memory for a deserialized declaration. /// /// This routine must be used to allocate memory for any declaration that is /// deserialized from a module file. /// /// \param Size The size of the allocated object. /// \param Ctx The context in which we will allocate memory. /// \param ID The global ID of the deserialized declaration. /// \param Extra The amount of extra space to allocate after the object. void *operator new(std::size_t Size, const ASTContext &Ctx, unsigned ID, std::size_t Extra = 0); /// \brief Allocate memory for a non-deserialized declaration. void *operator new(std::size_t Size, const ASTContext &Ctx, DeclContext *Parent, std::size_t Extra = 0); private: bool AccessDeclContextSanity() const; protected: Decl(Kind DK, DeclContext *DC, SourceLocation L) : NextInContextAndBits(), DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), Referenced(false), Access(AS_none), FromASTFile(0), Hidden(DC && cast(DC)->Hidden), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } Decl(Kind DK, EmptyShell Empty) : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), Referenced(false), Access(AS_none), FromASTFile(0), Hidden(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } virtual ~Decl(); /// \brief Update a potentially out-of-date declaration. void updateOutOfDate(IdentifierInfo &II) const; Linkage getCachedLinkage() const { return Linkage(CacheValidAndLinkage - 1); } void setCachedLinkage(Linkage L) const { CacheValidAndLinkage = L + 1; } bool hasCachedLinkage() const { return CacheValidAndLinkage; } public: /// \brief Source range that this declaration covers. virtual SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getLocation(), getLocation()); } SourceLocation getLocStart() const LLVM_READONLY { return getSourceRange().getBegin(); } SourceLocation getLocEnd() const LLVM_READONLY { return getSourceRange().getEnd(); } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } Kind getKind() const { return static_cast(DeclKind); } const char *getDeclKindName() const; Decl *getNextDeclInContext() { return NextInContextAndBits.getPointer(); } const Decl *getNextDeclInContext() const {return NextInContextAndBits.getPointer();} DeclContext *getDeclContext() { if (isInSemaDC()) return getSemanticDC(); return getMultipleDC()->SemanticDC; } const DeclContext *getDeclContext() const { return const_cast(this)->getDeclContext(); } /// Find the innermost non-closure ancestor of this declaration, /// walking up through blocks, lambdas, etc. If that ancestor is /// not a code context (!isFunctionOrMethod()), returns null. /// /// A declaration may be its own non-closure context. Decl *getNonClosureContext(); const Decl *getNonClosureContext() const { return const_cast(this)->getNonClosureContext(); } TranslationUnitDecl *getTranslationUnitDecl(); const TranslationUnitDecl *getTranslationUnitDecl() const { return const_cast(this)->getTranslationUnitDecl(); } bool isInAnonymousNamespace() const; bool isInStdNamespace() const; ASTContext &getASTContext() const LLVM_READONLY; void setAccess(AccessSpecifier AS) { Access = AS; assert(AccessDeclContextSanity()); } AccessSpecifier getAccess() const { assert(AccessDeclContextSanity()); return AccessSpecifier(Access); } /// \brief Retrieve the access specifier for this declaration, even though /// it may not yet have been properly set. AccessSpecifier getAccessUnsafe() const { return AccessSpecifier(Access); } bool hasAttrs() const { return HasAttrs; } void setAttrs(const AttrVec& Attrs) { return setAttrsImpl(Attrs, getASTContext()); } AttrVec &getAttrs() { return const_cast(const_cast(this)->getAttrs()); } const AttrVec &getAttrs() const; void dropAttrs(); void addAttr(Attr *A) { if (hasAttrs()) getAttrs().push_back(A); else setAttrs(AttrVec(1, A)); } typedef AttrVec::const_iterator attr_iterator; typedef llvm::iterator_range attr_range; attr_range attrs() const { return attr_range(attr_begin(), attr_end()); } attr_iterator attr_begin() const { return hasAttrs() ? getAttrs().begin() : nullptr; } attr_iterator attr_end() const { return hasAttrs() ? getAttrs().end() : nullptr; } template void dropAttr() { if (!HasAttrs) return; AttrVec &Vec = getAttrs(); Vec.erase(std::remove_if(Vec.begin(), Vec.end(), isa), Vec.end()); if (Vec.empty()) HasAttrs = false; } template llvm::iterator_range> specific_attrs() const { return llvm::make_range(specific_attr_begin(), specific_attr_end()); } template specific_attr_iterator specific_attr_begin() const { return specific_attr_iterator(attr_begin()); } template specific_attr_iterator specific_attr_end() const { return specific_attr_iterator(attr_end()); } template T *getAttr() const { return hasAttrs() ? getSpecificAttr(getAttrs()) : nullptr; } template bool hasAttr() const { return hasAttrs() && hasSpecificAttr(getAttrs()); } /// getMaxAlignment - return the maximum alignment specified by attributes /// on this decl, 0 if there are none. unsigned getMaxAlignment() const; /// setInvalidDecl - Indicates the Decl had a semantic error. This /// allows for graceful error recovery. void setInvalidDecl(bool Invalid = true); bool isInvalidDecl() const { return (bool) InvalidDecl; } /// isImplicit - Indicates whether the declaration was implicitly /// generated by the implementation. If false, this declaration /// was written explicitly in the source code. bool isImplicit() const { return Implicit; } void setImplicit(bool I = true) { Implicit = I; } /// \brief Whether *any* (re-)declaration of the entity was used, meaning that /// a definition is required. /// /// \param CheckUsedAttr When true, also consider the "used" attribute /// (in addition to the "used" bit set by \c setUsed()) when determining /// whether the function is used. bool isUsed(bool CheckUsedAttr = true) const; /// \brief Set whether the declaration is used, in the sense of odr-use. /// /// This should only be used immediately after creating a declaration. /// It intentionally doesn't notify any listeners. void setIsUsed() { getCanonicalDecl()->Used = true; } /// \brief Mark the declaration used, in the sense of odr-use. /// /// This notifies any mutation listeners in addition to setting a bit /// indicating the declaration is used. void markUsed(ASTContext &C); /// \brief Whether any declaration of this entity was referenced. bool isReferenced() const; /// \brief Whether this declaration was referenced. This should not be relied /// upon for anything other than debugging. bool isThisDeclarationReferenced() const { return Referenced; } void setReferenced(bool R = true) { Referenced = R; } /// \brief Whether this declaration is a top-level declaration (function, /// global variable, etc.) that is lexically inside an objc container /// definition. bool isTopLevelDeclInObjCContainer() const { return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag; } void setTopLevelDeclInObjCContainer(bool V = true) { unsigned Bits = NextInContextAndBits.getInt(); if (V) Bits |= TopLevelDeclInObjCContainerFlag; else Bits &= ~TopLevelDeclInObjCContainerFlag; NextInContextAndBits.setInt(Bits); } /// \brief Whether this declaration was marked as being private to the /// module in which it was defined. bool isModulePrivate() const { return NextInContextAndBits.getInt() & ModulePrivateFlag; } /// \brief Whether this declaration is exported (by virtue of being lexically /// within an ExportDecl or by being a NamespaceDecl). bool isExported() const; /// Return true if this declaration has an attribute which acts as /// definition of the entity, such as 'alias' or 'ifunc'. bool hasDefiningAttr() const; /// Return this declaration's defining attribute if it has one. const Attr *getDefiningAttr() const; protected: /// \brief Specify whether this declaration was marked as being private /// to the module in which it was defined. void setModulePrivate(bool MP = true) { unsigned Bits = NextInContextAndBits.getInt(); if (MP) Bits |= ModulePrivateFlag; else Bits &= ~ModulePrivateFlag; NextInContextAndBits.setInt(Bits); } /// \brief Set the owning module ID. void setOwningModuleID(unsigned ID) { assert(isFromASTFile() && "Only works on a deserialized declaration"); *((unsigned*)this - 2) = ID; } public: /// \brief Determine the availability of the given declaration. /// /// This routine will determine the most restrictive availability of /// the given declaration (e.g., preferring 'unavailable' to /// 'deprecated'). /// /// \param Message If non-NULL and the result is not \c /// AR_Available, will be set to a (possibly empty) message /// describing why the declaration has not been introduced, is /// deprecated, or is unavailable. /// /// \param EnclosingVersion The version to compare with. If empty, assume the /// deployment target version. AvailabilityResult getAvailability(std::string *Message = nullptr, VersionTuple EnclosingVersion = VersionTuple()) const; /// \brief Retrieve the version of the target platform in which this /// declaration was introduced. /// /// \returns An empty version tuple if this declaration has no 'introduced' /// availability attributes, or the version tuple that's specified in the /// attribute otherwise. VersionTuple getVersionIntroduced() const; /// \brief Determine whether this declaration is marked 'deprecated'. /// /// \param Message If non-NULL and the declaration is deprecated, /// this will be set to the message describing why the declaration /// was deprecated (which may be empty). bool isDeprecated(std::string *Message = nullptr) const { return getAvailability(Message) == AR_Deprecated; } /// \brief Determine whether this declaration is marked 'unavailable'. /// /// \param Message If non-NULL and the declaration is unavailable, /// this will be set to the message describing why the declaration /// was made unavailable (which may be empty). bool isUnavailable(std::string *Message = nullptr) const { return getAvailability(Message) == AR_Unavailable; } /// \brief Determine whether this is a weak-imported symbol. /// /// Weak-imported symbols are typically marked with the /// 'weak_import' attribute, but may also be marked with an /// 'availability' attribute where we're targing a platform prior to /// the introduction of this feature. bool isWeakImported() const; /// \brief Determines whether this symbol can be weak-imported, /// e.g., whether it would be well-formed to add the weak_import /// attribute. /// /// \param IsDefinition Set to \c true to indicate that this /// declaration cannot be weak-imported because it has a definition. bool canBeWeakImported(bool &IsDefinition) const; /// \brief Determine whether this declaration came from an AST file (such as /// a precompiled header or module) rather than having been parsed. bool isFromASTFile() const { return FromASTFile; } /// \brief Retrieve the global declaration ID associated with this /// declaration, which specifies where this Decl was loaded from. unsigned getGlobalID() const { if (isFromASTFile()) return *((const unsigned*)this - 1); return 0; } /// \brief Retrieve the global ID of the module that owns this particular /// declaration. unsigned getOwningModuleID() const { if (isFromASTFile()) return *((const unsigned*)this - 2); return 0; } private: Module *getOwningModuleSlow() const; protected: bool hasLocalOwningModuleStorage() const; public: /// \brief Get the imported owning module, if this decl is from an imported /// (non-local) module. Module *getImportedOwningModule() const { if (!isFromASTFile()) return nullptr; return getOwningModuleSlow(); } /// \brief Get the local owning module, if known. Returns nullptr if owner is /// not yet known or declaration is not from a module. Module *getLocalOwningModule() const { if (isFromASTFile() || !Hidden) return nullptr; return reinterpret_cast(this)[-1]; } void setLocalOwningModule(Module *M) { assert(!isFromASTFile() && Hidden && hasLocalOwningModuleStorage() && "should not have a cached owning module"); reinterpret_cast(this)[-1] = M; } + Module *getOwningModule() const { + return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule(); + } + + /// \brief Determine whether this declaration is hidden from name lookup. + bool isHidden() const { return Hidden; } + + /// \brief Set whether this declaration is hidden from name lookup. + void setHidden(bool Hide) { + assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) && + "declaration with no owning module can't be hidden"); + Hidden = Hide; + } + unsigned getIdentifierNamespace() const { return IdentifierNamespace; } bool isInIdentifierNamespace(unsigned NS) const { return getIdentifierNamespace() & NS; } static unsigned getIdentifierNamespaceForKind(Kind DK); bool hasTagIdentifierNamespace() const { return isTagIdentifierNamespace(getIdentifierNamespace()); } static bool isTagIdentifierNamespace(unsigned NS) { // TagDecls have Tag and Type set and may also have TagFriend. return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type); } /// getLexicalDeclContext - The declaration context where this Decl was /// lexically declared (LexicalDC). May be different from /// getDeclContext() (SemanticDC). /// e.g.: /// /// namespace A { /// void f(); // SemanticDC == LexicalDC == 'namespace A' /// } /// void A::f(); // SemanticDC == namespace 'A' /// // LexicalDC == global namespace DeclContext *getLexicalDeclContext() { if (isInSemaDC()) return getSemanticDC(); return getMultipleDC()->LexicalDC; } const DeclContext *getLexicalDeclContext() const { return const_cast(this)->getLexicalDeclContext(); } /// Determine whether this declaration is declared out of line (outside its /// semantic context). virtual bool isOutOfLine() const; /// setDeclContext - Set both the semantic and lexical DeclContext /// to DC. void setDeclContext(DeclContext *DC); void setLexicalDeclContext(DeclContext *DC); /// isDefinedOutsideFunctionOrMethod - This predicate returns true if this /// scoped decl is defined outside the current function or method. This is /// roughly global variables and functions, but also handles enums (which /// could be defined inside or outside a function etc). bool isDefinedOutsideFunctionOrMethod() const { return getParentFunctionOrMethod() == nullptr; } /// \brief Returns true if this declaration lexically is inside a function. /// It recognizes non-defining declarations as well as members of local /// classes: /// \code /// void foo() { void bar(); } /// void foo2() { class ABC { void bar(); }; } /// \endcode bool isLexicallyWithinFunctionOrMethod() const; /// \brief If this decl is defined inside a function/method/block it returns /// the corresponding DeclContext, otherwise it returns null. const DeclContext *getParentFunctionOrMethod() const; DeclContext *getParentFunctionOrMethod() { return const_cast( const_cast(this)->getParentFunctionOrMethod()); } /// \brief Retrieves the "canonical" declaration of the given declaration. virtual Decl *getCanonicalDecl() { return this; } const Decl *getCanonicalDecl() const { return const_cast(this)->getCanonicalDecl(); } /// \brief Whether this particular Decl is a canonical one. bool isCanonicalDecl() const { return getCanonicalDecl() == this; } protected: /// \brief Returns the next redeclaration or itself if this is the only decl. /// /// Decl subclasses that can be redeclared should override this method so that /// Decl::redecl_iterator can iterate over them. virtual Decl *getNextRedeclarationImpl() { return this; } /// \brief Implementation of getPreviousDecl(), to be overridden by any /// subclass that has a redeclaration chain. virtual Decl *getPreviousDeclImpl() { return nullptr; } /// \brief Implementation of getMostRecentDecl(), to be overridden by any /// subclass that has a redeclaration chain. virtual Decl *getMostRecentDeclImpl() { return this; } public: /// \brief Iterates through all the redeclarations of the same decl. class redecl_iterator { /// Current - The current declaration. Decl *Current; Decl *Starter; public: typedef Decl *value_type; typedef const value_type &reference; typedef const value_type *pointer; typedef std::forward_iterator_tag iterator_category; typedef std::ptrdiff_t difference_type; redecl_iterator() : Current(nullptr) { } explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { } reference operator*() const { return Current; } value_type operator->() const { return Current; } redecl_iterator& operator++() { assert(Current && "Advancing while iterator has reached end"); // Get either previous decl or latest decl. Decl *Next = Current->getNextRedeclarationImpl(); assert(Next && "Should return next redeclaration or itself, never null!"); Current = (Next != Starter) ? Next : nullptr; return *this; } redecl_iterator operator++(int) { redecl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(redecl_iterator x, redecl_iterator y) { return x.Current == y.Current; } friend bool operator!=(redecl_iterator x, redecl_iterator y) { return x.Current != y.Current; } }; typedef llvm::iterator_range redecl_range; /// \brief Returns an iterator range for all the redeclarations of the same /// decl. It will iterate at least once (when this decl is the only one). redecl_range redecls() const { return redecl_range(redecls_begin(), redecls_end()); } redecl_iterator redecls_begin() const { return redecl_iterator(const_cast(this)); } redecl_iterator redecls_end() const { return redecl_iterator(); } /// \brief Retrieve the previous declaration that declares the same entity /// as this declaration, or NULL if there is no previous declaration. Decl *getPreviousDecl() { return getPreviousDeclImpl(); } /// \brief Retrieve the most recent declaration that declares the same entity /// as this declaration, or NULL if there is no previous declaration. const Decl *getPreviousDecl() const { return const_cast(this)->getPreviousDeclImpl(); } /// \brief True if this is the first declaration in its redeclaration chain. bool isFirstDecl() const { return getPreviousDecl() == nullptr; } /// \brief Retrieve the most recent declaration that declares the same entity /// as this declaration (which may be this declaration). Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); } /// \brief Retrieve the most recent declaration that declares the same entity /// as this declaration (which may be this declaration). const Decl *getMostRecentDecl() const { return const_cast(this)->getMostRecentDeclImpl(); } /// getBody - If this Decl represents a declaration for a body of code, /// such as a function or method definition, this method returns the /// top-level Stmt* of that body. Otherwise this method returns null. virtual Stmt* getBody() const { return nullptr; } /// \brief Returns true if this \c Decl represents a declaration for a body of /// code, such as a function or method definition. /// Note that \c hasBody can also return true if any redeclaration of this /// \c Decl represents a declaration for a body of code. virtual bool hasBody() const { return getBody() != nullptr; } /// getBodyRBrace - Gets the right brace of the body, if a body exists. /// This works whether the body is a CompoundStmt or a CXXTryStmt. SourceLocation getBodyRBrace() const; // global temp stats (until we have a per-module visitor) static void add(Kind k); static void EnableStatistics(); static void PrintStats(); /// isTemplateParameter - Determines whether this declaration is a /// template parameter. bool isTemplateParameter() const; /// isTemplateParameter - Determines whether this declaration is a /// template parameter pack. bool isTemplateParameterPack() const; /// \brief Whether this declaration is a parameter pack. bool isParameterPack() const; /// \brief returns true if this declaration is a template bool isTemplateDecl() const; /// \brief Whether this declaration is a function or function template. bool isFunctionOrFunctionTemplate() const { return (DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction) || DeclKind == FunctionTemplate; } /// \brief If this is a declaration that describes some template, this /// method returns that template declaration. TemplateDecl *getDescribedTemplate() const; /// \brief Returns the function itself, or the templated function if this is a /// function template. FunctionDecl *getAsFunction() LLVM_READONLY; const FunctionDecl *getAsFunction() const { return const_cast(this)->getAsFunction(); } /// \brief Changes the namespace of this declaration to reflect that it's /// a function-local extern declaration. /// /// These declarations appear in the lexical context of the extern /// declaration, but in the semantic context of the enclosing namespace /// scope. void setLocalExternDecl() { assert((IdentifierNamespace == IDNS_Ordinary || IdentifierNamespace == IDNS_OrdinaryFriend) && "namespace is not ordinary"); Decl *Prev = getPreviousDecl(); IdentifierNamespace &= ~IDNS_Ordinary; IdentifierNamespace |= IDNS_LocalExtern; if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary) IdentifierNamespace |= IDNS_Ordinary; } /// \brief Determine whether this is a block-scope declaration with linkage. /// This will either be a local variable declaration declared 'extern', or a /// local function declaration. bool isLocalExternDecl() { return IdentifierNamespace & IDNS_LocalExtern; } /// \brief Changes the namespace of this declaration to reflect that it's /// the object of a friend declaration. /// /// These declarations appear in the lexical context of the friending /// class, but in the semantic context of the actual entity. This property /// applies only to a specific decl object; other redeclarations of the /// same entity may not (and probably don't) share this property. void setObjectOfFriendDecl(bool PerformFriendInjection = false) { unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFriend | IDNS_LocalExtern)) && "namespace includes neither ordinary nor tag"); assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | IDNS_TagFriend | IDNS_OrdinaryFriend | IDNS_LocalExtern)) && "namespace includes other than ordinary or tag"); Decl *Prev = getPreviousDecl(); IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type); if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { IdentifierNamespace |= IDNS_TagFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Tag)) IdentifierNamespace |= IDNS_Tag | IDNS_Type; } if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) { IdentifierNamespace |= IDNS_OrdinaryFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)) IdentifierNamespace |= IDNS_Ordinary; } } enum FriendObjectKind { FOK_None, ///< Not a friend object. FOK_Declared, ///< A friend of a previously-declared entity. FOK_Undeclared ///< A friend of a previously-undeclared entity. }; /// \brief Determines whether this declaration is the object of a /// friend declaration and, if so, what kind. /// /// There is currently no direct way to find the associated FriendDecl. FriendObjectKind getFriendObjectKind() const { unsigned mask = (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend)); if (!mask) return FOK_None; return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared : FOK_Undeclared); } /// Specifies that this declaration is a C++ overloaded non-member. void setNonMemberOperator() { assert(getKind() == Function || getKind() == FunctionTemplate); assert((IdentifierNamespace & IDNS_Ordinary) && "visible non-member operators should be in ordinary namespace"); IdentifierNamespace |= IDNS_NonMemberOperator; } static bool classofKind(Kind K) { return true; } static DeclContext *castToDeclContext(const Decl *); static Decl *castFromDeclContext(const DeclContext *); void print(raw_ostream &Out, unsigned Indentation = 0, bool PrintInstantiation = false) const; void print(raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0, bool PrintInstantiation = false) const; static void printGroup(Decl** Begin, unsigned NumDecls, raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0); // Debuggers don't usually respect default arguments. void dump() const; // Same as dump(), but forces color printing. void dumpColor() const; void dump(raw_ostream &Out, bool Deserialize = false) const; /// \brief Looks through the Decl's underlying type to extract a FunctionType /// when possible. Will return null if the type underlying the Decl does not /// have a FunctionType. const FunctionType *getFunctionType(bool BlocksToo = true) const; private: void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx); void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, ASTContext &Ctx); protected: ASTMutationListener *getASTMutationListener() const; }; /// \brief Determine whether two declarations declare the same entity. inline bool declaresSameEntity(const Decl *D1, const Decl *D2) { if (!D1 || !D2) return false; if (D1 == D2) return true; return D1->getCanonicalDecl() == D2->getCanonicalDecl(); } /// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when /// doing something to a specific decl. class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { const Decl *TheDecl; SourceLocation Loc; SourceManager &SM; const char *Message; public: PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L, SourceManager &sm, const char *Msg) : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} void print(raw_ostream &OS) const override; }; /// \brief The results of name lookup within a DeclContext. This is either a /// single result (with no stable storage) or a collection of results (with /// stable storage provided by the lookup table). class DeclContextLookupResult { typedef ArrayRef ResultTy; ResultTy Result; // If there is only one lookup result, it would be invalidated by // reallocations of the name table, so store it separately. NamedDecl *Single; static NamedDecl *const SingleElementDummyList; public: DeclContextLookupResult() : Result(), Single() {} DeclContextLookupResult(ArrayRef Result) : Result(Result), Single() {} DeclContextLookupResult(NamedDecl *Single) : Result(SingleElementDummyList), Single(Single) {} class iterator; typedef llvm::iterator_adaptor_base IteratorBase; class iterator : public IteratorBase { value_type SingleElement; public: iterator() : IteratorBase(), SingleElement() {} explicit iterator(pointer Pos, value_type Single = nullptr) : IteratorBase(Pos), SingleElement(Single) {} reference operator*() const { return SingleElement ? SingleElement : IteratorBase::operator*(); } }; typedef iterator const_iterator; typedef iterator::pointer pointer; typedef iterator::reference reference; iterator begin() const { return iterator(Result.begin(), Single); } iterator end() const { return iterator(Result.end(), Single); } bool empty() const { return Result.empty(); } pointer data() const { return Single ? &Single : Result.data(); } size_t size() const { return Single ? 1 : Result.size(); } reference front() const { return Single ? Single : Result.front(); } reference back() const { return Single ? Single : Result.back(); } reference operator[](size_t N) const { return Single ? Single : Result[N]; } // FIXME: Remove this from the interface DeclContextLookupResult slice(size_t N) const { DeclContextLookupResult Sliced = Result.slice(N); Sliced.Single = Single; return Sliced; } }; /// DeclContext - This is used only as base class of specific decl types that /// can act as declaration contexts. These decls are (only the top classes /// that directly derive from DeclContext are mentioned, not their subclasses): /// /// TranslationUnitDecl /// NamespaceDecl /// FunctionDecl /// TagDecl /// ObjCMethodDecl /// ObjCContainerDecl /// LinkageSpecDecl /// ExportDecl /// BlockDecl /// OMPDeclareReductionDecl /// class DeclContext { /// DeclKind - This indicates which class this is. unsigned DeclKind : 8; /// \brief Whether this declaration context also has some external /// storage that contains additional declarations that are lexically /// part of this context. mutable bool ExternalLexicalStorage : 1; /// \brief Whether this declaration context also has some external /// storage that contains additional declarations that are visible /// in this context. mutable bool ExternalVisibleStorage : 1; /// \brief Whether this declaration context has had external visible /// storage added since the last lookup. In this case, \c LookupPtr's /// invariant may not hold and needs to be fixed before we perform /// another lookup. mutable bool NeedToReconcileExternalVisibleStorage : 1; /// \brief If \c true, this context may have local lexical declarations /// that are missing from the lookup table. mutable bool HasLazyLocalLexicalLookups : 1; /// \brief If \c true, the external source may have lexical declarations /// that are missing from the lookup table. mutable bool HasLazyExternalLexicalLookups : 1; /// \brief If \c true, lookups should only return identifier from /// DeclContext scope (for example TranslationUnit). Used in /// LookupQualifiedName() mutable bool UseQualifiedLookup : 1; /// \brief Pointer to the data structure used to lookup declarations /// within this context (or a DependentStoredDeclsMap if this is a /// dependent context). We maintain the invariant that, if the map /// contains an entry for a DeclarationName (and we haven't lazily /// omitted anything), then it contains all relevant entries for that /// name (modulo the hasExternalDecls() flag). mutable StoredDeclsMap *LookupPtr; protected: /// FirstDecl - The first declaration stored within this declaration /// context. mutable Decl *FirstDecl; /// LastDecl - The last declaration stored within this declaration /// context. FIXME: We could probably cache this value somewhere /// outside of the DeclContext, to reduce the size of DeclContext by /// another pointer. mutable Decl *LastDecl; friend class ExternalASTSource; friend class ASTDeclReader; friend class ASTWriter; /// \brief Build up a chain of declarations. /// /// \returns the first/last pair of declarations. static std::pair BuildDeclChain(ArrayRef Decls, bool FieldsAlreadyLoaded); DeclContext(Decl::Kind K) : DeclKind(K), ExternalLexicalStorage(false), ExternalVisibleStorage(false), NeedToReconcileExternalVisibleStorage(false), HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false), UseQualifiedLookup(false), LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {} public: ~DeclContext(); Decl::Kind getDeclKind() const { return static_cast(DeclKind); } const char *getDeclKindName() const; /// getParent - Returns the containing DeclContext. DeclContext *getParent() { return cast(this)->getDeclContext(); } const DeclContext *getParent() const { return const_cast(this)->getParent(); } /// getLexicalParent - Returns the containing lexical DeclContext. May be /// different from getParent, e.g.: /// /// namespace A { /// struct S; /// } /// struct A::S {}; // getParent() == namespace 'A' /// // getLexicalParent() == translation unit /// DeclContext *getLexicalParent() { return cast(this)->getLexicalDeclContext(); } const DeclContext *getLexicalParent() const { return const_cast(this)->getLexicalParent(); } DeclContext *getLookupParent(); const DeclContext *getLookupParent() const { return const_cast(this)->getLookupParent(); } ASTContext &getParentASTContext() const { return cast(this)->getASTContext(); } bool isClosure() const { return DeclKind == Decl::Block; } bool isObjCContainer() const { switch (DeclKind) { case Decl::ObjCCategory: case Decl::ObjCCategoryImpl: case Decl::ObjCImplementation: case Decl::ObjCInterface: case Decl::ObjCProtocol: return true; } return false; } bool isFunctionOrMethod() const { switch (DeclKind) { case Decl::Block: case Decl::Captured: case Decl::ObjCMethod: return true; default: return DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction; } } /// \brief Test whether the context supports looking up names. bool isLookupContext() const { return !isFunctionOrMethod() && DeclKind != Decl::LinkageSpec && DeclKind != Decl::Export; } bool isFileContext() const { return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace; } bool isTranslationUnit() const { return DeclKind == Decl::TranslationUnit; } bool isRecord() const { return DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord; } bool isNamespace() const { return DeclKind == Decl::Namespace; } bool isStdNamespace() const; bool isInlineNamespace() const; /// \brief Determines whether this context is dependent on a /// template parameter. bool isDependentContext() const; /// isTransparentContext - Determines whether this context is a /// "transparent" context, meaning that the members declared in this /// context are semantically declared in the nearest enclosing /// non-transparent (opaque) context but are lexically declared in /// this context. For example, consider the enumerators of an /// enumeration type: /// @code /// enum E { /// Val1 /// }; /// @endcode /// Here, E is a transparent context, so its enumerator (Val1) will /// appear (semantically) that it is in the same context of E. /// Examples of transparent contexts include: enumerations (except for /// C++0x scoped enums), and C++ linkage specifications. bool isTransparentContext() const; /// \brief Determines whether this context or some of its ancestors is a /// linkage specification context that specifies C linkage. bool isExternCContext() const; /// \brief Retrieve the nearest enclosing C linkage specification context. const LinkageSpecDecl *getExternCContext() const; /// \brief Determines whether this context or some of its ancestors is a /// linkage specification context that specifies C++ linkage. bool isExternCXXContext() const; /// \brief Determine whether this declaration context is equivalent /// to the declaration context DC. bool Equals(const DeclContext *DC) const { return DC && this->getPrimaryContext() == DC->getPrimaryContext(); } /// \brief Determine whether this declaration context encloses the /// declaration context DC. bool Encloses(const DeclContext *DC) const; /// \brief Find the nearest non-closure ancestor of this context, /// i.e. the innermost semantic parent of this context which is not /// a closure. A context may be its own non-closure ancestor. Decl *getNonClosureAncestor(); const Decl *getNonClosureAncestor() const { return const_cast(this)->getNonClosureAncestor(); } /// getPrimaryContext - There may be many different /// declarations of the same entity (including forward declarations /// of classes, multiple definitions of namespaces, etc.), each with /// a different set of declarations. This routine returns the /// "primary" DeclContext structure, which will contain the /// information needed to perform name lookup into this context. DeclContext *getPrimaryContext(); const DeclContext *getPrimaryContext() const { return const_cast(this)->getPrimaryContext(); } /// getRedeclContext - Retrieve the context in which an entity conflicts with /// other entities of the same name, or where it is a redeclaration if the /// two entities are compatible. This skips through transparent contexts. DeclContext *getRedeclContext(); const DeclContext *getRedeclContext() const { return const_cast(this)->getRedeclContext(); } /// \brief Retrieve the nearest enclosing namespace context. DeclContext *getEnclosingNamespaceContext(); const DeclContext *getEnclosingNamespaceContext() const { return const_cast(this)->getEnclosingNamespaceContext(); } /// \brief Retrieve the outermost lexically enclosing record context. RecordDecl *getOuterLexicalRecordContext(); const RecordDecl *getOuterLexicalRecordContext() const { return const_cast(this)->getOuterLexicalRecordContext(); } /// \brief Test if this context is part of the enclosing namespace set of /// the context NS, as defined in C++0x [namespace.def]p9. If either context /// isn't a namespace, this is equivalent to Equals(). /// /// The enclosing namespace set of a namespace is the namespace and, if it is /// inline, its enclosing namespace, recursively. bool InEnclosingNamespaceSetOf(const DeclContext *NS) const; /// \brief Collects all of the declaration contexts that are semantically /// connected to this declaration context. /// /// For declaration contexts that have multiple semantically connected but /// syntactically distinct contexts, such as C++ namespaces, this routine /// retrieves the complete set of such declaration contexts in source order. /// For example, given: /// /// \code /// namespace N { /// int x; /// } /// namespace N { /// int y; /// } /// \endcode /// /// The \c Contexts parameter will contain both definitions of N. /// /// \param Contexts Will be cleared and set to the set of declaration /// contexts that are semanticaly connected to this declaration context, /// in source order, including this context (which may be the only result, /// for non-namespace contexts). void collectAllContexts(SmallVectorImpl &Contexts); /// decl_iterator - Iterates through the declarations stored /// within this context. class decl_iterator { /// Current - The current declaration. Decl *Current; public: typedef Decl *value_type; typedef const value_type &reference; typedef const value_type *pointer; typedef std::forward_iterator_tag iterator_category; typedef std::ptrdiff_t difference_type; decl_iterator() : Current(nullptr) { } explicit decl_iterator(Decl *C) : Current(C) { } reference operator*() const { return Current; } // This doesn't meet the iterator requirements, but it's convenient value_type operator->() const { return Current; } decl_iterator& operator++() { Current = Current->getNextDeclInContext(); return *this; } decl_iterator operator++(int) { decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(decl_iterator x, decl_iterator y) { return x.Current == y.Current; } friend bool operator!=(decl_iterator x, decl_iterator y) { return x.Current != y.Current; } }; typedef llvm::iterator_range decl_range; /// decls_begin/decls_end - Iterate over the declarations stored in /// this context. decl_range decls() const { return decl_range(decls_begin(), decls_end()); } decl_iterator decls_begin() const; decl_iterator decls_end() const { return decl_iterator(); } bool decls_empty() const; /// noload_decls_begin/end - Iterate over the declarations stored in this /// context that are currently loaded; don't attempt to retrieve anything /// from an external source. decl_range noload_decls() const { return decl_range(noload_decls_begin(), noload_decls_end()); } decl_iterator noload_decls_begin() const { return decl_iterator(FirstDecl); } decl_iterator noload_decls_end() const { return decl_iterator(); } /// specific_decl_iterator - Iterates over a subrange of /// declarations stored in a DeclContext, providing only those that /// are of type SpecificDecl (or a class derived from it). This /// iterator is used, for example, to provide iteration over just /// the fields within a RecordDecl (with SpecificDecl = FieldDecl). template class specific_decl_iterator { /// Current - The current, underlying declaration iterator, which /// will either be NULL or will point to a declaration of /// type SpecificDecl. DeclContext::decl_iterator Current; /// SkipToNextDecl - Advances the current position up to the next /// declaration of type SpecificDecl that also meets the criteria /// required by Acceptable. void SkipToNextDecl() { while (*Current && !isa(*Current)) ++Current; } public: typedef SpecificDecl *value_type; // TODO: Add reference and pointer typedefs (with some appropriate proxy // type) if we ever have a need for them. typedef void reference; typedef void pointer; typedef std::iterator_traits::difference_type difference_type; typedef std::forward_iterator_tag iterator_category; specific_decl_iterator() : Current() { } /// specific_decl_iterator - Construct a new iterator over a /// subset of the declarations the range [C, /// end-of-declarations). If A is non-NULL, it is a pointer to a /// member function of SpecificDecl that should return true for /// all of the SpecificDecl instances that will be in the subset /// of iterators. For example, if you want Objective-C instance /// methods, SpecificDecl will be ObjCMethodDecl and A will be /// &ObjCMethodDecl::isInstanceMethod. explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) { SkipToNextDecl(); } value_type operator*() const { return cast(*Current); } // This doesn't meet the iterator requirements, but it's convenient value_type operator->() const { return **this; } specific_decl_iterator& operator++() { ++Current; SkipToNextDecl(); return *this; } specific_decl_iterator operator++(int) { specific_decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) { return x.Current == y.Current; } friend bool operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) { return x.Current != y.Current; } }; /// \brief Iterates over a filtered subrange of declarations stored /// in a DeclContext. /// /// This iterator visits only those declarations that are of type /// SpecificDecl (or a class derived from it) and that meet some /// additional run-time criteria. This iterator is used, for /// example, to provide access to the instance methods within an /// Objective-C interface (with SpecificDecl = ObjCMethodDecl and /// Acceptable = ObjCMethodDecl::isInstanceMethod). template class filtered_decl_iterator { /// Current - The current, underlying declaration iterator, which /// will either be NULL or will point to a declaration of /// type SpecificDecl. DeclContext::decl_iterator Current; /// SkipToNextDecl - Advances the current position up to the next /// declaration of type SpecificDecl that also meets the criteria /// required by Acceptable. void SkipToNextDecl() { while (*Current && (!isa(*Current) || (Acceptable && !(cast(*Current)->*Acceptable)()))) ++Current; } public: typedef SpecificDecl *value_type; // TODO: Add reference and pointer typedefs (with some appropriate proxy // type) if we ever have a need for them. typedef void reference; typedef void pointer; typedef std::iterator_traits::difference_type difference_type; typedef std::forward_iterator_tag iterator_category; filtered_decl_iterator() : Current() { } /// filtered_decl_iterator - Construct a new iterator over a /// subset of the declarations the range [C, /// end-of-declarations). If A is non-NULL, it is a pointer to a /// member function of SpecificDecl that should return true for /// all of the SpecificDecl instances that will be in the subset /// of iterators. For example, if you want Objective-C instance /// methods, SpecificDecl will be ObjCMethodDecl and A will be /// &ObjCMethodDecl::isInstanceMethod. explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) { SkipToNextDecl(); } value_type operator*() const { return cast(*Current); } value_type operator->() const { return cast(*Current); } filtered_decl_iterator& operator++() { ++Current; SkipToNextDecl(); return *this; } filtered_decl_iterator operator++(int) { filtered_decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { return x.Current == y.Current; } friend bool operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { return x.Current != y.Current; } }; /// @brief Add the declaration D into this context. /// /// This routine should be invoked when the declaration D has first /// been declared, to place D into the context where it was /// (lexically) defined. Every declaration must be added to one /// (and only one!) context, where it can be visited via /// [decls_begin(), decls_end()). Once a declaration has been added /// to its lexical context, the corresponding DeclContext owns the /// declaration. /// /// If D is also a NamedDecl, it will be made visible within its /// semantic context via makeDeclVisibleInContext. void addDecl(Decl *D); /// @brief Add the declaration D into this context, but suppress /// searches for external declarations with the same name. /// /// Although analogous in function to addDecl, this removes an /// important check. This is only useful if the Decl is being /// added in response to an external search; in all other cases, /// addDecl() is the right function to use. /// See the ASTImporter for use cases. void addDeclInternal(Decl *D); /// @brief Add the declaration D to this context without modifying /// any lookup tables. /// /// This is useful for some operations in dependent contexts where /// the semantic context might not be dependent; this basically /// only happens with friends. void addHiddenDecl(Decl *D); /// @brief Removes a declaration from this context. void removeDecl(Decl *D); /// @brief Checks whether a declaration is in this context. bool containsDecl(Decl *D) const; typedef DeclContextLookupResult lookup_result; typedef lookup_result::iterator lookup_iterator; /// lookup - Find the declarations (if any) with the given Name in /// this context. Returns a range of iterators that contains all of /// the declarations with this name, with object, function, member, /// and enumerator names preceding any tag name. Note that this /// routine will not look into parent contexts. lookup_result lookup(DeclarationName Name) const; /// \brief Find the declarations with the given name that are visible /// within this context; don't attempt to retrieve anything from an /// external source. lookup_result noload_lookup(DeclarationName Name); /// \brief A simplistic name lookup mechanism that performs name lookup /// into this declaration context without consulting the external source. /// /// This function should almost never be used, because it subverts the /// usual relationship between a DeclContext and the external source. /// See the ASTImporter for the (few, but important) use cases. /// /// FIXME: This is very inefficient; replace uses of it with uses of /// noload_lookup. void localUncachedLookup(DeclarationName Name, SmallVectorImpl &Results); /// @brief Makes a declaration visible within this context. /// /// This routine makes the declaration D visible to name lookup /// within this context and, if this is a transparent context, /// within its parent contexts up to the first enclosing /// non-transparent context. Making a declaration visible within a /// context does not transfer ownership of a declaration, and a /// declaration can be visible in many contexts that aren't its /// lexical context. /// /// If D is a redeclaration of an existing declaration that is /// visible from this context, as determined by /// NamedDecl::declarationReplaces, the previous declaration will be /// replaced with D. void makeDeclVisibleInContext(NamedDecl *D); /// all_lookups_iterator - An iterator that provides a view over the results /// of looking up every possible name. class all_lookups_iterator; typedef llvm::iterator_range lookups_range; lookups_range lookups() const; lookups_range noload_lookups() const; /// \brief Iterators over all possible lookups within this context. all_lookups_iterator lookups_begin() const; all_lookups_iterator lookups_end() const; /// \brief Iterators over all possible lookups within this context that are /// currently loaded; don't attempt to retrieve anything from an external /// source. all_lookups_iterator noload_lookups_begin() const; all_lookups_iterator noload_lookups_end() const; struct udir_iterator; typedef llvm::iterator_adaptor_base udir_iterator_base; struct udir_iterator : udir_iterator_base { udir_iterator(lookup_iterator I) : udir_iterator_base(I) {} UsingDirectiveDecl *operator*() const; }; typedef llvm::iterator_range udir_range; udir_range using_directives() const; // These are all defined in DependentDiagnostic.h. class ddiag_iterator; typedef llvm::iterator_range ddiag_range; inline ddiag_range ddiags() const; // Low-level accessors /// \brief Mark that there are external lexical declarations that we need /// to include in our lookup table (and that are not available as external /// visible lookups). These extra lookup results will be found by walking /// the lexical declarations of this context. This should be used only if /// setHasExternalLexicalStorage() has been called on any decl context for /// which this is the primary context. void setMustBuildLookupTable() { assert(this == getPrimaryContext() && "should only be called on primary context"); HasLazyExternalLexicalLookups = true; } /// \brief Retrieve the internal representation of the lookup structure. /// This may omit some names if we are lazily building the structure. StoredDeclsMap *getLookupPtr() const { return LookupPtr; } /// \brief Ensure the lookup structure is fully-built and return it. StoredDeclsMap *buildLookup(); /// \brief Whether this DeclContext has external storage containing /// additional declarations that are lexically in this context. bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; } /// \brief State whether this DeclContext has external storage for /// declarations lexically in this context. void setHasExternalLexicalStorage(bool ES = true) { ExternalLexicalStorage = ES; } /// \brief Whether this DeclContext has external storage containing /// additional declarations that are visible in this context. bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; } /// \brief State whether this DeclContext has external storage for /// declarations visible in this context. void setHasExternalVisibleStorage(bool ES = true) { ExternalVisibleStorage = ES; if (ES && LookupPtr) NeedToReconcileExternalVisibleStorage = true; } /// \brief Determine whether the given declaration is stored in the list of /// declarations lexically within this context. bool isDeclInLexicalTraversal(const Decl *D) const { return D && (D->NextInContextAndBits.getPointer() || D == FirstDecl || D == LastDecl); } bool setUseQualifiedLookup(bool use = true) { bool old_value = UseQualifiedLookup; UseQualifiedLookup = use; return old_value; } bool shouldUseQualifiedLookup() const { return UseQualifiedLookup; } static bool classof(const Decl *D); static bool classof(const DeclContext *D) { return true; } void dumpDeclContext() const; void dumpLookups() const; void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false, bool Deserialize = false) const; private: void reconcileExternalVisibleStorage() const; bool LoadLexicalDeclsFromExternalStorage() const; /// @brief Makes a declaration visible within this context, but /// suppresses searches for external declarations with the same /// name. /// /// Analogous to makeDeclVisibleInContext, but for the exclusive /// use of addDeclInternal(). void makeDeclVisibleInContextInternal(NamedDecl *D); friend class DependentDiagnostic; StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; void buildLookupImpl(DeclContext *DCtx, bool Internal); void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, bool Rediscoverable); void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal); }; inline bool Decl::isTemplateParameter() const { return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm || getKind() == TemplateTemplateParm; } // Specialization selected when ToTy is not a known subclass of DeclContext. template ::value> struct cast_convert_decl_context { static const ToTy *doit(const DeclContext *Val) { return static_cast(Decl::castFromDeclContext(Val)); } static ToTy *doit(DeclContext *Val) { return static_cast(Decl::castFromDeclContext(Val)); } }; // Specialization selected when ToTy is a known subclass of DeclContext. template struct cast_convert_decl_context { static const ToTy *doit(const DeclContext *Val) { return static_cast(Val); } static ToTy *doit(DeclContext *Val) { return static_cast(Val); } }; } // end clang. namespace llvm { /// isa(DeclContext*) template struct isa_impl { static bool doit(const ::clang::DeclContext &Val) { return To::classofKind(Val.getDeclKind()); } }; /// cast(DeclContext*) template struct cast_convert_val { static const ToTy &doit(const ::clang::DeclContext &Val) { return *::clang::cast_convert_decl_context::doit(&Val); } }; template struct cast_convert_val { static ToTy &doit(::clang::DeclContext &Val) { return *::clang::cast_convert_decl_context::doit(&Val); } }; template struct cast_convert_val { static const ToTy *doit(const ::clang::DeclContext *Val) { return ::clang::cast_convert_decl_context::doit(Val); } }; template struct cast_convert_val { static ToTy *doit(::clang::DeclContext *Val) { return ::clang::cast_convert_decl_context::doit(Val); } }; /// Implement cast_convert_val for Decl -> DeclContext conversions. template struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> { static ::clang::DeclContext &doit(const FromTy &Val) { return *FromTy::castToDeclContext(&Val); } }; template struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> { static ::clang::DeclContext *doit(const FromTy *Val) { return FromTy::castToDeclContext(Val); } }; template struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> { static const ::clang::DeclContext &doit(const FromTy &Val) { return *FromTy::castToDeclContext(&Val); } }; template struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { static const ::clang::DeclContext *doit(const FromTy *Val) { return FromTy::castToDeclContext(Val); } }; } // end namespace llvm #endif Index: vendor/clang/dist/include/clang/Basic/LangOptions.h =================================================================== --- vendor/clang/dist/include/clang/Basic/LangOptions.h (revision 318415) +++ vendor/clang/dist/include/clang/Basic/LangOptions.h (revision 318416) @@ -1,243 +1,248 @@ //===--- LangOptions.h - C Language Family Language Options -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Defines the clang::LangOptions interface. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_LANGOPTIONS_H #define LLVM_CLANG_BASIC_LANGOPTIONS_H #include "clang/Basic/CommentOptions.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Basic/Visibility.h" #include #include namespace clang { /// Bitfields of LangOptions, split out from LangOptions in order to ensure that /// this large collection of bitfields is a trivial class type. class LangOptionsBase { public: // Define simple language options (with no accessors). #define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits; #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" protected: // Define language options of enumeration type. These are private, and will // have accessors (below). #define LANGOPT(Name, Bits, Default, Description) #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ unsigned Name : Bits; #include "clang/Basic/LangOptions.def" }; /// \brief Keeps track of the various options that can be /// enabled, which controls the dialect of C or C++ that is accepted. class LangOptions : public LangOptionsBase { public: typedef clang::Visibility Visibility; enum GCMode { NonGC, GCOnly, HybridGC }; enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq }; enum SignedOverflowBehaviorTy { SOB_Undefined, // Default C standard behavior. SOB_Defined, // -fwrapv SOB_Trapping // -ftrapv }; enum CompilingModuleKind { CMK_None, ///< Not compiling a module interface at all. CMK_ModuleMap, ///< Compiling a module from a module map. CMK_ModuleInterface ///< Compiling a C++ modules TS module interface unit. }; enum PragmaMSPointersToMembersKind { PPTMK_BestCase, PPTMK_FullGeneralitySingleInheritance, PPTMK_FullGeneralityMultipleInheritance, PPTMK_FullGeneralityVirtualInheritance }; enum DefaultCallingConvention { DCC_None, DCC_CDecl, DCC_FastCall, DCC_StdCall, DCC_VectorCall }; enum AddrSpaceMapMangling { ASMM_Target, ASMM_On, ASMM_Off }; enum MSVCMajorVersion { MSVC2010 = 16, MSVC2012 = 17, MSVC2013 = 18, MSVC2015 = 19 }; enum FPContractModeKind { FPC_Off, // Form fused FP ops only where result will not be affected. FPC_On, // Form fused FP ops according to FP_CONTRACT rules. FPC_Fast // Aggressively fuse FP ops (E.g. FMA). }; public: /// \brief Set of enabled sanitizers. SanitizerSet Sanitize; /// \brief Paths to blacklist files specifying which objects /// (files, functions, variables) should not be instrumented. std::vector SanitizerBlacklistFiles; /// \brief Paths to the XRay "always instrument" files specifying which /// objects (files, functions, variables) should be imbued with the XRay /// "always instrument" attribute. std::vector XRayAlwaysInstrumentFiles; /// \brief Paths to the XRay "never instrument" files specifying which /// objects (files, functions, variables) should be imbued with the XRay /// "never instrument" attribute. std::vector XRayNeverInstrumentFiles; clang::ObjCRuntime ObjCRuntime; std::string ObjCConstantStringClass; /// \brief The name of the handler function to be called when -ftrapv is /// specified. /// /// If none is specified, abort (GCC-compatible behaviour). std::string OverflowHandler; /// \brief The name of the current module, of which the main source file /// is a part. If CompilingModule is set, we are compiling the interface /// of this module, otherwise we are compiling an implementation file of /// it. std::string CurrentModule; /// \brief The names of any features to enable in module 'requires' decls /// in addition to the hard-coded list in Module.cpp and the target features. /// /// This list is sorted. std::vector ModuleFeatures; /// \brief Options for parsing comments. CommentOptions CommentOpts; /// \brief A list of all -fno-builtin-* function names (e.g., memset). std::vector NoBuiltinFuncs; /// \brief Triples of the OpenMP targets that the host code codegen should /// take into account in order to generate accurate offloading descriptors. std::vector OMPTargetTriples; /// \brief Name of the IR file that contains the result of the OpenMP target /// host code generation. std::string OMPHostIRFile; /// \brief Indicates whether the front-end is explicitly told that the /// input is a header file (i.e. -x c-header). bool IsHeaderFile; LangOptions(); // Define accessors/mutators for language options of enumeration type. #define LANGOPT(Name, Bits, Default, Description) #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ Type get##Name() const { return static_cast(Name); } \ void set##Name(Type Value) { Name = static_cast(Value); } #include "clang/Basic/LangOptions.def" /// Are we compiling a module interface (.cppm or module map)? bool isCompilingModule() const { return getCompilingModule() != CMK_None; } + /// Do we need to track the owning module for a local declaration? + bool trackLocalOwningModule() const { + return ModulesLocalVisibility; + } + bool isSignedOverflowDefined() const { return getSignedOverflowBehavior() == SOB_Defined; } bool isSubscriptPointerArithmetic() const { return ObjCRuntime.isSubscriptPointerArithmetic() && !ObjCSubscriptingLegacyRuntime; } bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const { return MSCompatibilityVersion >= MajorVersion * 10000000U; } /// \brief Reset all of the options that are not considered when building a /// module. void resetNonModularOptions(); /// \brief Is this a libc/libm function that is no longer recognized as a /// builtin because a -fno-builtin-* option has been specified? bool isNoBuiltinFunc(StringRef Name) const; /// \brief True if any ObjC types may have non-trivial lifetime qualifiers. bool allowsNonTrivialObjCLifetimeQualifiers() const { return ObjCAutoRefCount || ObjCWeak; } }; /// \brief Floating point control options class FPOptions { public: FPOptions() : fp_contract(LangOptions::FPC_Off) {} // Used for serializing. explicit FPOptions(unsigned I) : fp_contract(static_cast(I)) {} explicit FPOptions(const LangOptions &LangOpts) : fp_contract(LangOpts.getDefaultFPContractMode()) {} bool allowFPContractWithinStatement() const { return fp_contract == LangOptions::FPC_On; } bool allowFPContractAcrossStatement() const { return fp_contract == LangOptions::FPC_Fast; } void setAllowFPContractWithinStatement() { fp_contract = LangOptions::FPC_On; } void setAllowFPContractAcrossStatement() { fp_contract = LangOptions::FPC_Fast; } void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; } /// Used to serialize this. unsigned getInt() const { return fp_contract; } private: /// Adjust BinaryOperator::FPFeatures to match the bit-field size of this. unsigned fp_contract : 2; }; /// \brief Describes the kind of translation unit being processed. enum TranslationUnitKind { /// \brief The translation unit is a complete translation unit. TU_Complete, /// \brief The translation unit is a prefix to a translation unit, and is /// not complete. TU_Prefix, /// \brief The translation unit is a module. TU_Module }; } // end namespace clang #endif Index: vendor/clang/dist/include/clang/Basic/SourceManager.h =================================================================== --- vendor/clang/dist/include/clang/Basic/SourceManager.h (revision 318415) +++ vendor/clang/dist/include/clang/Basic/SourceManager.h (revision 318416) @@ -1,1725 +1,1725 @@ //===--- SourceManager.h - Track and cache source files ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Defines the SourceManager interface. /// /// There are three different types of locations in a %file: a spelling /// location, an expansion location, and a presumed location. /// /// Given an example of: /// \code /// #define min(x, y) x < y ? x : y /// \endcode /// /// and then later on a use of min: /// \code /// #line 17 /// return min(a, b); /// \endcode /// /// The expansion location is the line in the source code where the macro /// was expanded (the return statement), the spelling location is the /// location in the source where the macro was originally defined, /// and the presumed location is where the line directive states that /// the line is 17, or any other line. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_SOURCEMANAGER_H #define LLVM_CLANG_BASIC_SOURCEMANAGER_H #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include #include #include #include #include #include #include #include #include namespace clang { class ASTReader; class ASTWriter; class DiagnosticsEngine; class LineTableInfo; class SourceManager; /// \brief Public enums and private classes that are part of the /// SourceManager implementation. /// namespace SrcMgr { /// \brief Indicates whether a file or directory holds normal user code, /// system code, or system code which is implicitly 'extern "C"' in C++ mode. /// /// Entire directories can be tagged with this (this is maintained by /// DirectoryLookup and friends) as can specific FileInfos when a \#pragma /// system_header is seen or in various other cases. /// enum CharacteristicKind { C_User, C_System, C_ExternCSystem }; /// \brief One instance of this struct is kept for every file loaded or used. /// /// This object owns the MemoryBuffer object. class LLVM_ALIGNAS(8) ContentCache { enum CCFlags { /// \brief Whether the buffer is invalid. InvalidFlag = 0x01, /// \brief Whether the buffer should not be freed on destruction. DoNotFreeFlag = 0x02 }; /// \brief The actual buffer containing the characters from the input /// file. /// /// This is owned by the ContentCache object. The bits indicate /// whether the buffer is invalid. mutable llvm::PointerIntPair Buffer; public: /// \brief Reference to the file entry representing this ContentCache. /// /// This reference does not own the FileEntry object. /// /// It is possible for this to be NULL if the ContentCache encapsulates /// an imaginary text buffer. const FileEntry *OrigEntry; /// \brief References the file which the contents were actually loaded from. /// /// Can be different from 'Entry' if we overridden the contents of one file /// with the contents of another file. const FileEntry *ContentsEntry; /// \brief A bump pointer allocated array of offsets for each source line. /// /// This is lazily computed. This is owned by the SourceManager /// BumpPointerAllocator object. unsigned *SourceLineCache; /// \brief The number of lines in this ContentCache. /// /// This is only valid if SourceLineCache is non-null. unsigned NumLines; /// \brief Indicates whether the buffer itself was provided to override /// the actual file contents. /// /// When true, the original entry may be a virtual file that does not /// exist. unsigned BufferOverridden : 1; /// \brief True if this content cache was initially created for a source /// file considered as a system one. unsigned IsSystemFile : 1; /// \brief True if this file may be transient, that is, if it might not /// exist at some later point in time when this content entry is used, /// after serialization and deserialization. unsigned IsTransient : 1; ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {} ContentCache(const FileEntry *Ent, const FileEntry *contentEnt) : Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt), SourceLineCache(nullptr), NumLines(0), BufferOverridden(false), IsSystemFile(false), IsTransient(false) {} /// The copy ctor does not allow copies where source object has either /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory /// is not transferred, so this is a logical error. ContentCache(const ContentCache &RHS) : Buffer(nullptr, false), SourceLineCache(nullptr), BufferOverridden(false), IsSystemFile(false), IsTransient(false) { OrigEntry = RHS.OrigEntry; ContentsEntry = RHS.ContentsEntry; assert(RHS.Buffer.getPointer() == nullptr && RHS.SourceLineCache == nullptr && "Passed ContentCache object cannot own a buffer."); NumLines = RHS.NumLines; } ContentCache &operator=(const ContentCache& RHS) = delete; ~ContentCache(); /// \brief Returns the memory buffer for the associated content. /// /// \param Diag Object through which diagnostics will be emitted if the /// buffer cannot be retrieved. /// /// \param Loc If specified, is the location that invalid file diagnostics /// will be emitted at. /// /// \param Invalid If non-NULL, will be set \c true if an error occurred. llvm::MemoryBuffer *getBuffer(DiagnosticsEngine &Diag, const SourceManager &SM, SourceLocation Loc = SourceLocation(), bool *Invalid = nullptr) const; /// \brief Returns the size of the content encapsulated by this /// ContentCache. /// /// This can be the size of the source file or the size of an /// arbitrary scratch buffer. If the ContentCache encapsulates a source /// file this size is retrieved from the file's FileEntry. unsigned getSize() const; /// \brief Returns the number of bytes actually mapped for this /// ContentCache. /// /// This can be 0 if the MemBuffer was not actually expanded. unsigned getSizeBytesMapped() const; /// Returns the kind of memory used to back the memory buffer for /// this content cache. This is used for performance analysis. llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const; void setBuffer(std::unique_ptr B) { assert(!Buffer.getPointer() && "MemoryBuffer already set."); Buffer.setPointer(B.release()); Buffer.setInt(0); } /// \brief Get the underlying buffer, returning NULL if the buffer is not /// yet available. llvm::MemoryBuffer *getRawBuffer() const { return Buffer.getPointer(); } /// \brief Replace the existing buffer (which will be deleted) /// with the given buffer. void replaceBuffer(llvm::MemoryBuffer *B, bool DoNotFree = false); /// \brief Determine whether the buffer itself is invalid. bool isBufferInvalid() const { return Buffer.getInt() & InvalidFlag; } /// \brief Determine whether the buffer should be freed. bool shouldFreeBuffer() const { return (Buffer.getInt() & DoNotFreeFlag) == 0; } }; // Assert that the \c ContentCache objects will always be 8-byte aligned so // that we can pack 3 bits of integer into pointers to such objects. static_assert(alignof(ContentCache) >= 8, "ContentCache must be 8-byte aligned."); /// \brief Information about a FileID, basically just the logical file /// that it represents and include stack information. /// /// Each FileInfo has include stack information, indicating where it came /// from. This information encodes the \#include chain that a token was /// expanded from. The main include file has an invalid IncludeLoc. /// /// FileInfos contain a "ContentCache *", with the contents of the file. /// class FileInfo { /// \brief The location of the \#include that brought in this file. /// /// This is an invalid SLOC for the main file (top of the \#include chain). unsigned IncludeLoc; // Really a SourceLocation /// \brief Number of FileIDs (files and macros) that were created during /// preprocessing of this \#include, including this SLocEntry. /// /// Zero means the preprocessor didn't provide such info for this SLocEntry. unsigned NumCreatedFIDs; /// \brief Contains the ContentCache* and the bits indicating the /// characteristic of the file and whether it has \#line info, all /// bitmangled together. uintptr_t Data; friend class clang::SourceManager; friend class clang::ASTWriter; friend class clang::ASTReader; public: /// \brief Return a FileInfo object. static FileInfo get(SourceLocation IL, const ContentCache *Con, CharacteristicKind FileCharacter) { FileInfo X; X.IncludeLoc = IL.getRawEncoding(); X.NumCreatedFIDs = 0; X.Data = (uintptr_t)Con; assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned"); assert((unsigned)FileCharacter < 4 && "invalid file character"); X.Data |= (unsigned)FileCharacter; return X; } SourceLocation getIncludeLoc() const { return SourceLocation::getFromRawEncoding(IncludeLoc); } const ContentCache* getContentCache() const { return reinterpret_cast(Data & ~uintptr_t(7)); } /// \brief Return whether this is a system header or not. CharacteristicKind getFileCharacteristic() const { return (CharacteristicKind)(Data & 3); } /// \brief Return true if this FileID has \#line directives in it. bool hasLineDirectives() const { return (Data & 4) != 0; } /// \brief Set the flag that indicates that this FileID has /// line table entries associated with it. void setHasLineDirectives() { Data |= 4; } }; /// \brief Each ExpansionInfo encodes the expansion location - where /// the token was ultimately expanded, and the SpellingLoc - where the actual /// character data for the token came from. class ExpansionInfo { // Really these are all SourceLocations. /// \brief Where the spelling for the token can be found. unsigned SpellingLoc; /// In a macro expansion, ExpansionLocStart and ExpansionLocEnd /// indicate the start and end of the expansion. In object-like macros, /// they will be the same. In a function-like macro expansion, the start /// will be the identifier and the end will be the ')'. Finally, in /// macro-argument instantiations, the end will be 'SourceLocation()', an /// invalid location. unsigned ExpansionLocStart, ExpansionLocEnd; public: SourceLocation getSpellingLoc() const { return SourceLocation::getFromRawEncoding(SpellingLoc); } SourceLocation getExpansionLocStart() const { return SourceLocation::getFromRawEncoding(ExpansionLocStart); } SourceLocation getExpansionLocEnd() const { SourceLocation EndLoc = SourceLocation::getFromRawEncoding(ExpansionLocEnd); return EndLoc.isInvalid() ? getExpansionLocStart() : EndLoc; } std::pair getExpansionLocRange() const { return std::make_pair(getExpansionLocStart(), getExpansionLocEnd()); } bool isMacroArgExpansion() const { // Note that this needs to return false for default constructed objects. return getExpansionLocStart().isValid() && SourceLocation::getFromRawEncoding(ExpansionLocEnd).isInvalid(); } bool isMacroBodyExpansion() const { return getExpansionLocStart().isValid() && SourceLocation::getFromRawEncoding(ExpansionLocEnd).isValid(); } bool isFunctionMacroExpansion() const { return getExpansionLocStart().isValid() && getExpansionLocStart() != getExpansionLocEnd(); } /// \brief Return a ExpansionInfo for an expansion. /// /// Start and End specify the expansion range (where the macro is /// expanded), and SpellingLoc specifies the spelling location (where /// the characters from the token come from). All three can refer to /// normal File SLocs or expansion locations. static ExpansionInfo create(SourceLocation SpellingLoc, SourceLocation Start, SourceLocation End) { ExpansionInfo X; X.SpellingLoc = SpellingLoc.getRawEncoding(); X.ExpansionLocStart = Start.getRawEncoding(); X.ExpansionLocEnd = End.getRawEncoding(); return X; } /// \brief Return a special ExpansionInfo for the expansion of /// a macro argument into a function-like macro's body. /// /// ExpansionLoc specifies the expansion location (where the macro is /// expanded). This doesn't need to be a range because a macro is always /// expanded at a macro parameter reference, and macro parameters are /// always exactly one token. SpellingLoc specifies the spelling location /// (where the characters from the token come from). ExpansionLoc and /// SpellingLoc can both refer to normal File SLocs or expansion locations. /// /// Given the code: /// \code /// #define F(x) f(x) /// F(42); /// \endcode /// /// When expanding '\c F(42)', the '\c x' would call this with an /// SpellingLoc pointing at '\c 42' and an ExpansionLoc pointing at its /// location in the definition of '\c F'. static ExpansionInfo createForMacroArg(SourceLocation SpellingLoc, SourceLocation ExpansionLoc) { // We store an intentionally invalid source location for the end of the // expansion range to mark that this is a macro argument ion rather than // a normal one. return create(SpellingLoc, ExpansionLoc, SourceLocation()); } }; /// \brief This is a discriminated union of FileInfo and ExpansionInfo. /// /// SourceManager keeps an array of these objects, and they are uniquely /// identified by the FileID datatype. class SLocEntry { unsigned Offset : 31; unsigned IsExpansion : 1; union { FileInfo File; ExpansionInfo Expansion; }; public: unsigned getOffset() const { return Offset; } bool isExpansion() const { return IsExpansion; } bool isFile() const { return !isExpansion(); } const FileInfo &getFile() const { assert(isFile() && "Not a file SLocEntry!"); return File; } const ExpansionInfo &getExpansion() const { assert(isExpansion() && "Not a macro expansion SLocEntry!"); return Expansion; } static SLocEntry get(unsigned Offset, const FileInfo &FI) { assert(!(Offset & (1 << 31)) && "Offset is too large"); SLocEntry E; E.Offset = Offset; E.IsExpansion = false; E.File = FI; return E; } static SLocEntry get(unsigned Offset, const ExpansionInfo &Expansion) { assert(!(Offset & (1 << 31)) && "Offset is too large"); SLocEntry E; E.Offset = Offset; E.IsExpansion = true; E.Expansion = Expansion; return E; } }; } // end SrcMgr namespace. /// \brief External source of source location entries. class ExternalSLocEntrySource { public: virtual ~ExternalSLocEntrySource(); /// \brief Read the source location entry with index ID, which will always be /// less than -1. /// /// \returns true if an error occurred that prevented the source-location /// entry from being loaded. virtual bool ReadSLocEntry(int ID) = 0; /// \brief Retrieve the module import location and name for the given ID, if /// in fact it was loaded from a module (rather than, say, a precompiled /// header). virtual std::pair getModuleImportLoc(int ID) = 0; }; /// \brief Holds the cache used by isBeforeInTranslationUnit. /// /// The cache structure is complex enough to be worth breaking out of /// SourceManager. class InBeforeInTUCacheEntry { /// \brief The FileID's of the cached query. /// /// If these match up with a subsequent query, the result can be reused. FileID LQueryFID, RQueryFID; /// \brief True if LQueryFID was created before RQueryFID. /// /// This is used to compare macro expansion locations. bool IsLQFIDBeforeRQFID; /// \brief The file found in common between the two \#include traces, i.e., /// the nearest common ancestor of the \#include tree. FileID CommonFID; /// \brief The offset of the previous query in CommonFID. /// /// Usually, this represents the location of the \#include for QueryFID, but /// if LQueryFID is a parent of RQueryFID (or vice versa) then these can be a /// random token in the parent. unsigned LCommonOffset, RCommonOffset; public: /// \brief Return true if the currently cached values match up with /// the specified LHS/RHS query. /// /// If not, we can't use the cache. bool isCacheValid(FileID LHS, FileID RHS) const { return LQueryFID == LHS && RQueryFID == RHS; } /// \brief If the cache is valid, compute the result given the /// specified offsets in the LHS/RHS FileID's. bool getCachedResult(unsigned LOffset, unsigned ROffset) const { // If one of the query files is the common file, use the offset. Otherwise, // use the #include loc in the common file. if (LQueryFID != CommonFID) LOffset = LCommonOffset; if (RQueryFID != CommonFID) ROffset = RCommonOffset; // It is common for multiple macro expansions to be "included" from the same // location (expansion location), in which case use the order of the FileIDs // to determine which came first. This will also take care the case where // one of the locations points at the inclusion/expansion point of the other // in which case its FileID will come before the other. if (LOffset == ROffset) return IsLQFIDBeforeRQFID; return LOffset < ROffset; } /// \brief Set up a new query. void setQueryFIDs(FileID LHS, FileID RHS, bool isLFIDBeforeRFID) { assert(LHS != RHS); LQueryFID = LHS; RQueryFID = RHS; IsLQFIDBeforeRQFID = isLFIDBeforeRFID; } void clear() { LQueryFID = RQueryFID = FileID(); IsLQFIDBeforeRQFID = false; } void setCommonLoc(FileID commonFID, unsigned lCommonOffset, unsigned rCommonOffset) { CommonFID = commonFID; LCommonOffset = lCommonOffset; RCommonOffset = rCommonOffset; } }; /// \brief The stack used when building modules on demand, which is used /// to provide a link between the source managers of the different compiler /// instances. typedef ArrayRef> ModuleBuildStack; /// \brief This class handles loading and caching of source files into memory. /// /// This object owns the MemoryBuffer objects for all of the loaded /// files and assigns unique FileID's for each unique \#include chain. /// /// The SourceManager can be queried for information about SourceLocation /// objects, turning them into either spelling or expansion locations. Spelling /// locations represent where the bytes corresponding to a token came from and /// expansion locations represent where the location is in the user's view. In /// the case of a macro expansion, for example, the spelling location indicates /// where the expanded token came from and the expansion location specifies /// where it was expanded. class SourceManager : public RefCountedBase { /// \brief DiagnosticsEngine object. DiagnosticsEngine &Diag; FileManager &FileMgr; mutable llvm::BumpPtrAllocator ContentCacheAlloc; /// \brief Memoized information about all of the files tracked by this /// SourceManager. /// /// This map allows us to merge ContentCache entries based /// on their FileEntry*. All ContentCache objects will thus have unique, /// non-null, FileEntry pointers. llvm::DenseMap FileInfos; /// \brief True if the ContentCache for files that are overridden by other /// files, should report the original file name. Defaults to true. bool OverridenFilesKeepOriginalName; /// \brief True if non-system source files should be treated as volatile /// (likely to change while trying to use them). Defaults to false. bool UserFilesAreVolatile; /// \brief True if all files read during this compilation should be treated /// as transient (may not be present in later compilations using a module /// file created from this compilation). Defaults to false. bool FilesAreTransient; struct OverriddenFilesInfoTy { /// \brief Files that have been overridden with the contents from another /// file. llvm::DenseMap OverriddenFiles; /// \brief Files that were overridden with a memory buffer. llvm::DenseSet OverriddenFilesWithBuffer; }; /// \brief Lazily create the object keeping overridden files info, since /// it is uncommonly used. std::unique_ptr OverriddenFilesInfo; OverriddenFilesInfoTy &getOverriddenFilesInfo() { if (!OverriddenFilesInfo) OverriddenFilesInfo.reset(new OverriddenFilesInfoTy); return *OverriddenFilesInfo; } /// \brief Information about various memory buffers that we have read in. /// /// All FileEntry* within the stored ContentCache objects are NULL, /// as they do not refer to a file. std::vector MemBufferInfos; /// \brief The table of SLocEntries that are local to this module. /// /// Positive FileIDs are indexes into this table. Entry 0 indicates an invalid /// expansion. SmallVector LocalSLocEntryTable; /// \brief The table of SLocEntries that are loaded from other modules. /// /// Negative FileIDs are indexes into this table. To get from ID to an index, /// use (-ID - 2). mutable SmallVector LoadedSLocEntryTable; /// \brief The starting offset of the next local SLocEntry. /// /// This is LocalSLocEntryTable.back().Offset + the size of that entry. unsigned NextLocalOffset; /// \brief The starting offset of the latest batch of loaded SLocEntries. /// /// This is LoadedSLocEntryTable.back().Offset, except that that entry might /// not have been loaded, so that value would be unknown. unsigned CurrentLoadedOffset; /// \brief The highest possible offset is 2^31-1, so CurrentLoadedOffset /// starts at 2^31. static const unsigned MaxLoadedOffset = 1U << 31U; /// \brief A bitmap that indicates whether the entries of LoadedSLocEntryTable /// have already been loaded from the external source. /// /// Same indexing as LoadedSLocEntryTable. llvm::BitVector SLocEntryLoaded; /// \brief An external source for source location entries. ExternalSLocEntrySource *ExternalSLocEntries; /// \brief A one-entry cache to speed up getFileID. /// /// LastFileIDLookup records the last FileID looked up or created, because it /// is very common to look up many tokens from the same file. mutable FileID LastFileIDLookup; /// \brief Holds information for \#line directives. /// /// This is referenced by indices from SLocEntryTable. LineTableInfo *LineTable; /// \brief These ivars serve as a cache used in the getLineNumber /// method which is used to speedup getLineNumber calls to nearby locations. mutable FileID LastLineNoFileIDQuery; mutable SrcMgr::ContentCache *LastLineNoContentCache; mutable unsigned LastLineNoFilePos; mutable unsigned LastLineNoResult; /// \brief The file ID for the main source file of the translation unit. FileID MainFileID; /// \brief The file ID for the precompiled preamble there is one. FileID PreambleFileID; // Statistics for -print-stats. mutable unsigned NumLinearScans, NumBinaryProbes; /// \brief Associates a FileID with its "included/expanded in" decomposed /// location. /// /// Used to cache results from and speed-up \c getDecomposedIncludedLoc /// function. mutable llvm::DenseMap> IncludedLocMap; /// The key value into the IsBeforeInTUCache table. typedef std::pair IsBeforeInTUCacheKey; /// The IsBeforeInTranslationUnitCache is a mapping from FileID pairs /// to cache results. typedef llvm::DenseMap InBeforeInTUCache; /// Cache results for the isBeforeInTranslationUnit method. mutable InBeforeInTUCache IBTUCache; mutable InBeforeInTUCacheEntry IBTUCacheOverflow; /// Return the cache entry for comparing the given file IDs /// for isBeforeInTranslationUnit. InBeforeInTUCacheEntry &getInBeforeInTUCache(FileID LFID, FileID RFID) const; // Cache for the "fake" buffer used for error-recovery purposes. mutable std::unique_ptr FakeBufferForRecovery; mutable std::unique_ptr FakeContentCacheForRecovery; /// \brief Lazily computed map of macro argument chunks to their expanded /// source location. typedef std::map MacroArgsMap; mutable llvm::DenseMap> MacroArgsCacheMap; /// \brief The stack of modules being built, which is used to detect /// cycles in the module dependency graph as modules are being built, as /// well as to describe why we're rebuilding a particular module. /// /// There is no way to set this value from the command line. If we ever need /// to do so (e.g., if on-demand module construction moves out-of-process), /// we can add a cc1-level option to do so. SmallVector, 2> StoredModuleBuildStack; public: SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr, bool UserFilesAreVolatile = false); explicit SourceManager(const SourceManager &) = delete; SourceManager &operator=(const SourceManager &) = delete; ~SourceManager(); void clearIDTables(); DiagnosticsEngine &getDiagnostics() const { return Diag; } FileManager &getFileManager() const { return FileMgr; } /// \brief Set true if the SourceManager should report the original file name /// for contents of files that were overridden by other files. Defaults to /// true. void setOverridenFilesKeepOriginalName(bool value) { OverridenFilesKeepOriginalName = value; } /// \brief True if non-system source files should be treated as volatile /// (likely to change while trying to use them). bool userFilesAreVolatile() const { return UserFilesAreVolatile; } /// \brief Retrieve the module build stack. ModuleBuildStack getModuleBuildStack() const { return StoredModuleBuildStack; } /// \brief Set the module build stack. void setModuleBuildStack(ModuleBuildStack stack) { StoredModuleBuildStack.clear(); StoredModuleBuildStack.append(stack.begin(), stack.end()); } /// \brief Push an entry to the module build stack. void pushModuleBuildStack(StringRef moduleName, FullSourceLoc importLoc) { StoredModuleBuildStack.push_back(std::make_pair(moduleName.str(),importLoc)); } //===--------------------------------------------------------------------===// // MainFileID creation and querying methods. //===--------------------------------------------------------------------===// /// \brief Returns the FileID of the main source file. FileID getMainFileID() const { return MainFileID; } /// \brief Set the file ID for the main source file. void setMainFileID(FileID FID) { MainFileID = FID; } /// \brief Set the file ID for the precompiled preamble. void setPreambleFileID(FileID Preamble) { assert(PreambleFileID.isInvalid() && "PreambleFileID already set!"); PreambleFileID = Preamble; } /// \brief Get the file ID for the precompiled preamble if there is one. FileID getPreambleFileID() const { return PreambleFileID; } //===--------------------------------------------------------------------===// // Methods to create new FileID's and macro expansions. //===--------------------------------------------------------------------===// /// \brief Create a new FileID that represents the specified file /// being \#included from the specified IncludePosition. /// /// This translates NULL into standard input. FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID = 0, unsigned LoadedOffset = 0) { const SrcMgr::ContentCache * IR = getOrCreateContentCache(SourceFile, /*isSystemFile=*/FileCharacter != SrcMgr::C_User); assert(IR && "getOrCreateContentCache() cannot return NULL"); return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset); } /// \brief Create a new FileID that represents the specified memory buffer. /// /// This does no caching of the buffer and takes ownership of the /// MemoryBuffer, so only pass a MemoryBuffer to this once. FileID createFileID(std::unique_ptr Buffer, SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, int LoadedID = 0, unsigned LoadedOffset = 0, SourceLocation IncludeLoc = SourceLocation()) { return createFileID(createMemBufferContentCache(std::move(Buffer)), IncludeLoc, FileCharacter, LoadedID, LoadedOffset); } /// \brief Get the FileID for \p SourceFile if it exists. Otherwise, create a /// new FileID for the \p SourceFile. FileID getOrCreateFileID(const FileEntry *SourceFile, SrcMgr::CharacteristicKind FileCharacter) { FileID ID = translateFile(SourceFile); return ID.isValid() ? ID : createFileID(SourceFile, SourceLocation(), FileCharacter); } /// \brief Return a new SourceLocation that encodes the /// fact that a token from SpellingLoc should actually be referenced from /// ExpansionLoc, and that it represents the expansion of a macro argument /// into the function-like macro body. SourceLocation createMacroArgExpansionLoc(SourceLocation Loc, SourceLocation ExpansionLoc, unsigned TokLength); /// \brief Return a new SourceLocation that encodes the fact /// that a token from SpellingLoc should actually be referenced from /// ExpansionLoc. SourceLocation createExpansionLoc(SourceLocation Loc, SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd, unsigned TokLength, int LoadedID = 0, unsigned LoadedOffset = 0); /// \brief Retrieve the memory buffer associated with the given file. /// /// \param Invalid If non-NULL, will be set \c true if an error /// occurs while retrieving the memory buffer. llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File, bool *Invalid = nullptr); /// \brief Override the contents of the given source file by providing an /// already-allocated buffer. /// /// \param SourceFile the source file whose contents will be overridden. /// /// \param Buffer the memory buffer whose contents will be used as the /// data in the given source file. /// /// \param DoNotFree If true, then the buffer will not be freed when the /// source manager is destroyed. void overrideFileContents(const FileEntry *SourceFile, llvm::MemoryBuffer *Buffer, bool DoNotFree); void overrideFileContents(const FileEntry *SourceFile, std::unique_ptr Buffer) { overrideFileContents(SourceFile, Buffer.release(), /*DoNotFree*/ false); } /// \brief Override the given source file with another one. /// /// \param SourceFile the source file which will be overridden. /// /// \param NewFile the file whose contents will be used as the /// data instead of the contents of the given source file. void overrideFileContents(const FileEntry *SourceFile, const FileEntry *NewFile); /// \brief Returns true if the file contents have been overridden. - bool isFileOverridden(const FileEntry *File) { + bool isFileOverridden(const FileEntry *File) const { if (OverriddenFilesInfo) { if (OverriddenFilesInfo->OverriddenFilesWithBuffer.count(File)) return true; if (OverriddenFilesInfo->OverriddenFiles.find(File) != OverriddenFilesInfo->OverriddenFiles.end()) return true; } return false; } /// \brief Disable overridding the contents of a file, previously enabled /// with #overrideFileContents. /// /// This should be called before parsing has begun. void disableFileContentsOverride(const FileEntry *File); /// \brief Specify that a file is transient. void setFileIsTransient(const FileEntry *SourceFile); /// \brief Specify that all files that are read during this compilation are /// transient. void setAllFilesAreTransient(bool Transient) { FilesAreTransient = Transient; } //===--------------------------------------------------------------------===// // FileID manipulation methods. //===--------------------------------------------------------------------===// /// \brief Return the buffer for the specified FileID. /// /// If there is an error opening this buffer the first time, this /// manufactures a temporary buffer and returns a non-empty error string. llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc, bool *Invalid = nullptr) const { bool MyInvalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); if (MyInvalid || !Entry.isFile()) { if (Invalid) *Invalid = true; return getFakeBufferForRecovery(); } return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc, Invalid); } llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = nullptr) const { bool MyInvalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); if (MyInvalid || !Entry.isFile()) { if (Invalid) *Invalid = true; return getFakeBufferForRecovery(); } return Entry.getFile().getContentCache()->getBuffer(Diag, *this, SourceLocation(), Invalid); } /// \brief Returns the FileEntry record for the provided FileID. const FileEntry *getFileEntryForID(FileID FID) const { bool MyInvalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); if (MyInvalid || !Entry.isFile()) return nullptr; const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache(); if (!Content) return nullptr; return Content->OrigEntry; } /// \brief Returns the FileEntry record for the provided SLocEntry. const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const { const SrcMgr::ContentCache *Content = sloc.getFile().getContentCache(); if (!Content) return nullptr; return Content->OrigEntry; } /// \brief Return a StringRef to the source buffer data for the /// specified FileID. /// /// \param FID The file ID whose contents will be returned. /// \param Invalid If non-NULL, will be set true if an error occurred. StringRef getBufferData(FileID FID, bool *Invalid = nullptr) const; /// \brief Get the number of FileIDs (files and macros) that were created /// during preprocessing of \p FID, including it. unsigned getNumCreatedFIDsForFileID(FileID FID) const { bool Invalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); if (Invalid || !Entry.isFile()) return 0; return Entry.getFile().NumCreatedFIDs; } /// \brief Set the number of FileIDs (files and macros) that were created /// during preprocessing of \p FID, including it. void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs) const { bool Invalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); if (Invalid || !Entry.isFile()) return; assert(Entry.getFile().NumCreatedFIDs == 0 && "Already set!"); const_cast(Entry.getFile()).NumCreatedFIDs = NumFIDs; } //===--------------------------------------------------------------------===// // SourceLocation manipulation methods. //===--------------------------------------------------------------------===// /// \brief Return the FileID for a SourceLocation. /// /// This is a very hot method that is used for all SourceManager queries /// that start with a SourceLocation object. It is responsible for finding /// the entry in SLocEntryTable which contains the specified location. /// FileID getFileID(SourceLocation SpellingLoc) const { unsigned SLocOffset = SpellingLoc.getOffset(); // If our one-entry cache covers this offset, just return it. if (isOffsetInFileID(LastFileIDLookup, SLocOffset)) return LastFileIDLookup; return getFileIDSlow(SLocOffset); } /// \brief Return the filename of the file containing a SourceLocation. StringRef getFilename(SourceLocation SpellingLoc) const { if (const FileEntry *F = getFileEntryForID(getFileID(SpellingLoc))) return F->getName(); return StringRef(); } /// \brief Return the source location corresponding to the first byte of /// the specified file. SourceLocation getLocForStartOfFile(FileID FID) const { bool Invalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); if (Invalid || !Entry.isFile()) return SourceLocation(); unsigned FileOffset = Entry.getOffset(); return SourceLocation::getFileLoc(FileOffset); } /// \brief Return the source location corresponding to the last byte of the /// specified file. SourceLocation getLocForEndOfFile(FileID FID) const { bool Invalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); if (Invalid || !Entry.isFile()) return SourceLocation(); unsigned FileOffset = Entry.getOffset(); return SourceLocation::getFileLoc(FileOffset + getFileIDSize(FID)); } /// \brief Returns the include location if \p FID is a \#include'd file /// otherwise it returns an invalid location. SourceLocation getIncludeLoc(FileID FID) const { bool Invalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); if (Invalid || !Entry.isFile()) return SourceLocation(); return Entry.getFile().getIncludeLoc(); } // \brief Returns the import location if the given source location is // located within a module, or an invalid location if the source location // is within the current translation unit. std::pair getModuleImportLoc(SourceLocation Loc) const { FileID FID = getFileID(Loc); // Positive file IDs are in the current translation unit, and -1 is a // placeholder. if (FID.ID >= -1) return std::make_pair(SourceLocation(), ""); return ExternalSLocEntries->getModuleImportLoc(FID.ID); } /// \brief Given a SourceLocation object \p Loc, return the expansion /// location referenced by the ID. SourceLocation getExpansionLoc(SourceLocation Loc) const { // Handle the non-mapped case inline, defer to out of line code to handle // expansions. if (Loc.isFileID()) return Loc; return getExpansionLocSlowCase(Loc); } /// \brief Given \p Loc, if it is a macro location return the expansion /// location or the spelling location, depending on if it comes from a /// macro argument or not. SourceLocation getFileLoc(SourceLocation Loc) const { if (Loc.isFileID()) return Loc; return getFileLocSlowCase(Loc); } /// \brief Return the start/end of the expansion information for an /// expansion location. /// /// \pre \p Loc is required to be an expansion location. std::pair getImmediateExpansionRange(SourceLocation Loc) const; /// \brief Given a SourceLocation object, return the range of /// tokens covered by the expansion in the ultimate file. std::pair getExpansionRange(SourceLocation Loc) const; /// \brief Given a SourceRange object, return the range of /// tokens covered by the expansion in the ultimate file. SourceRange getExpansionRange(SourceRange Range) const { return SourceRange(getExpansionRange(Range.getBegin()).first, getExpansionRange(Range.getEnd()).second); } /// \brief Given a SourceLocation object, return the spelling /// location referenced by the ID. /// /// This is the place where the characters that make up the lexed token /// can be found. SourceLocation getSpellingLoc(SourceLocation Loc) const { // Handle the non-mapped case inline, defer to out of line code to handle // expansions. if (Loc.isFileID()) return Loc; return getSpellingLocSlowCase(Loc); } /// \brief Given a SourceLocation object, return the spelling location /// referenced by the ID. /// /// This is the first level down towards the place where the characters /// that make up the lexed token can be found. This should not generally /// be used by clients. SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const; /// \brief Decompose the specified location into a raw FileID + Offset pair. /// /// The first element is the FileID, the second is the offset from the /// start of the buffer of the location. std::pair getDecomposedLoc(SourceLocation Loc) const { FileID FID = getFileID(Loc); bool Invalid = false; const SrcMgr::SLocEntry &E = getSLocEntry(FID, &Invalid); if (Invalid) return std::make_pair(FileID(), 0); return std::make_pair(FID, Loc.getOffset()-E.getOffset()); } /// \brief Decompose the specified location into a raw FileID + Offset pair. /// /// If the location is an expansion record, walk through it until we find /// the final location expanded. std::pair getDecomposedExpansionLoc(SourceLocation Loc) const { FileID FID = getFileID(Loc); bool Invalid = false; const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid); if (Invalid) return std::make_pair(FileID(), 0); unsigned Offset = Loc.getOffset()-E->getOffset(); if (Loc.isFileID()) return std::make_pair(FID, Offset); return getDecomposedExpansionLocSlowCase(E); } /// \brief Decompose the specified location into a raw FileID + Offset pair. /// /// If the location is an expansion record, walk through it until we find /// its spelling record. std::pair getDecomposedSpellingLoc(SourceLocation Loc) const { FileID FID = getFileID(Loc); bool Invalid = false; const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid); if (Invalid) return std::make_pair(FileID(), 0); unsigned Offset = Loc.getOffset()-E->getOffset(); if (Loc.isFileID()) return std::make_pair(FID, Offset); return getDecomposedSpellingLocSlowCase(E, Offset); } /// \brief Returns the "included/expanded in" decomposed location of the given /// FileID. std::pair getDecomposedIncludedLoc(FileID FID) const; /// \brief Returns the offset from the start of the file that the /// specified SourceLocation represents. /// /// This is not very meaningful for a macro ID. unsigned getFileOffset(SourceLocation SpellingLoc) const { return getDecomposedLoc(SpellingLoc).second; } /// \brief Tests whether the given source location represents a macro /// argument's expansion into the function-like macro definition. /// /// \param StartLoc If non-null and function returns true, it is set to the /// start location of the macro argument expansion. /// /// Such source locations only appear inside of the expansion /// locations representing where a particular function-like macro was /// expanded. bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc = nullptr) const; /// \brief Tests whether the given source location represents the expansion of /// a macro body. /// /// This is equivalent to testing whether the location is part of a macro /// expansion but not the expansion of an argument to a function-like macro. bool isMacroBodyExpansion(SourceLocation Loc) const; /// \brief Returns true if the given MacroID location points at the beginning /// of the immediate macro expansion. /// /// \param MacroBegin If non-null and function returns true, it is set to the /// begin location of the immediate macro expansion. bool isAtStartOfImmediateMacroExpansion(SourceLocation Loc, SourceLocation *MacroBegin = nullptr) const; /// \brief Returns true if the given MacroID location points at the character /// end of the immediate macro expansion. /// /// \param MacroEnd If non-null and function returns true, it is set to the /// character end location of the immediate macro expansion. bool isAtEndOfImmediateMacroExpansion(SourceLocation Loc, SourceLocation *MacroEnd = nullptr) const; /// \brief Returns true if \p Loc is inside the [\p Start, +\p Length) /// chunk of the source location address space. /// /// If it's true and \p RelativeOffset is non-null, it will be set to the /// relative offset of \p Loc inside the chunk. bool isInSLocAddrSpace(SourceLocation Loc, SourceLocation Start, unsigned Length, unsigned *RelativeOffset = nullptr) const { assert(((Start.getOffset() < NextLocalOffset && Start.getOffset()+Length <= NextLocalOffset) || (Start.getOffset() >= CurrentLoadedOffset && Start.getOffset()+Length < MaxLoadedOffset)) && "Chunk is not valid SLoc address space"); unsigned LocOffs = Loc.getOffset(); unsigned BeginOffs = Start.getOffset(); unsigned EndOffs = BeginOffs + Length; if (LocOffs >= BeginOffs && LocOffs < EndOffs) { if (RelativeOffset) *RelativeOffset = LocOffs - BeginOffs; return true; } return false; } /// \brief Return true if both \p LHS and \p RHS are in the local source /// location address space or the loaded one. /// /// If it's true and \p RelativeOffset is non-null, it will be set to the /// offset of \p RHS relative to \p LHS. bool isInSameSLocAddrSpace(SourceLocation LHS, SourceLocation RHS, int *RelativeOffset) const { unsigned LHSOffs = LHS.getOffset(), RHSOffs = RHS.getOffset(); bool LHSLoaded = LHSOffs >= CurrentLoadedOffset; bool RHSLoaded = RHSOffs >= CurrentLoadedOffset; if (LHSLoaded == RHSLoaded) { if (RelativeOffset) *RelativeOffset = RHSOffs - LHSOffs; return true; } return false; } //===--------------------------------------------------------------------===// // Queries about the code at a SourceLocation. //===--------------------------------------------------------------------===// /// \brief Return a pointer to the start of the specified location /// in the appropriate spelling MemoryBuffer. /// /// \param Invalid If non-NULL, will be set \c true if an error occurs. const char *getCharacterData(SourceLocation SL, bool *Invalid = nullptr) const; /// \brief Return the column # for the specified file position. /// /// This is significantly cheaper to compute than the line number. This /// returns zero if the column number isn't known. This may only be called /// on a file sloc, so you must choose a spelling or expansion location /// before calling this method. unsigned getColumnNumber(FileID FID, unsigned FilePos, bool *Invalid = nullptr) const; unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid = nullptr) const; unsigned getExpansionColumnNumber(SourceLocation Loc, bool *Invalid = nullptr) const; unsigned getPresumedColumnNumber(SourceLocation Loc, bool *Invalid = nullptr) const; /// \brief Given a SourceLocation, return the spelling line number /// for the position indicated. /// /// This requires building and caching a table of line offsets for the /// MemoryBuffer, so this is not cheap: use only when about to emit a /// diagnostic. unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = nullptr) const; unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const; unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const; unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const; /// \brief Return the filename or buffer identifier of the buffer the /// location is in. /// /// Note that this name does not respect \#line directives. Use /// getPresumedLoc for normal clients. StringRef getBufferName(SourceLocation Loc, bool *Invalid = nullptr) const; /// \brief Return the file characteristic of the specified source /// location, indicating whether this is a normal file, a system /// header, or an "implicit extern C" system header. /// /// This state can be modified with flags on GNU linemarker directives like: /// \code /// # 4 "foo.h" 3 /// \endcode /// which changes all source locations in the current file after that to be /// considered to be from a system header. SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const; /// \brief Returns the "presumed" location of a SourceLocation specifies. /// /// A "presumed location" can be modified by \#line or GNU line marker /// directives. This provides a view on the data that a user should see /// in diagnostics, for example. /// /// Note that a presumed location is always given as the expansion point of /// an expansion location, not at the spelling location. /// /// \returns The presumed location of the specified SourceLocation. If the /// presumed location cannot be calculated (e.g., because \p Loc is invalid /// or the file containing \p Loc has changed on disk), returns an invalid /// presumed location. PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives = true) const; /// \brief Returns whether the PresumedLoc for a given SourceLocation is /// in the main file. /// /// This computes the "presumed" location for a SourceLocation, then checks /// whether it came from a file other than the main file. This is different /// from isWrittenInMainFile() because it takes line marker directives into /// account. bool isInMainFile(SourceLocation Loc) const; /// \brief Returns true if the spelling locations for both SourceLocations /// are part of the same file buffer. /// /// This check ignores line marker directives. bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const { return getFileID(Loc1) == getFileID(Loc2); } /// \brief Returns true if the spelling location for the given location /// is in the main file buffer. /// /// This check ignores line marker directives. bool isWrittenInMainFile(SourceLocation Loc) const { return getFileID(Loc) == getMainFileID(); } /// \brief Returns if a SourceLocation is in a system header. bool isInSystemHeader(SourceLocation Loc) const { return getFileCharacteristic(Loc) != SrcMgr::C_User; } /// \brief Returns if a SourceLocation is in an "extern C" system header. bool isInExternCSystemHeader(SourceLocation Loc) const { return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem; } /// \brief Returns whether \p Loc is expanded from a macro in a system header. bool isInSystemMacro(SourceLocation loc) const { return loc.isMacroID() && isInSystemHeader(getSpellingLoc(loc)); } /// \brief The size of the SLocEntry that \p FID represents. unsigned getFileIDSize(FileID FID) const; /// \brief Given a specific FileID, returns true if \p Loc is inside that /// FileID chunk and sets relative offset (offset of \p Loc from beginning /// of FileID) to \p relativeOffset. bool isInFileID(SourceLocation Loc, FileID FID, unsigned *RelativeOffset = nullptr) const { unsigned Offs = Loc.getOffset(); if (isOffsetInFileID(FID, Offs)) { if (RelativeOffset) *RelativeOffset = Offs - getSLocEntry(FID).getOffset(); return true; } return false; } //===--------------------------------------------------------------------===// // Line Table Manipulation Routines //===--------------------------------------------------------------------===// /// \brief Return the uniqued ID for the specified filename. /// unsigned getLineTableFilenameID(StringRef Str); /// \brief Add a line note to the line table for the FileID and offset /// specified by Loc. /// /// If FilenameID is -1, it is considered to be unspecified. void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID); void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, bool IsFileEntry, bool IsFileExit, bool IsSystemHeader, bool IsExternCHeader); /// \brief Determine if the source manager has a line table. bool hasLineTable() const { return LineTable != nullptr; } /// \brief Retrieve the stored line table. LineTableInfo &getLineTable(); //===--------------------------------------------------------------------===// // Queries for performance analysis. //===--------------------------------------------------------------------===// /// \brief Return the total amount of physical memory allocated by the /// ContentCache allocator. size_t getContentCacheSize() const { return ContentCacheAlloc.getTotalMemory(); } struct MemoryBufferSizes { const size_t malloc_bytes; const size_t mmap_bytes; MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} }; /// \brief Return the amount of memory used by memory buffers, breaking down /// by heap-backed versus mmap'ed memory. MemoryBufferSizes getMemoryBufferSizes() const; /// \brief Return the amount of memory used for various side tables and /// data structures in the SourceManager. size_t getDataStructureSizes() const; //===--------------------------------------------------------------------===// // Other miscellaneous methods. //===--------------------------------------------------------------------===// /// \brief Get the source location for the given file:line:col triplet. /// /// If the source file is included multiple times, the source location will /// be based upon the first inclusion. SourceLocation translateFileLineCol(const FileEntry *SourceFile, unsigned Line, unsigned Col) const; /// \brief Get the FileID for the given file. /// /// If the source file is included multiple times, the FileID will be the /// first inclusion. FileID translateFile(const FileEntry *SourceFile) const; /// \brief Get the source location in \p FID for the given line:col. /// Returns null location if \p FID is not a file SLocEntry. SourceLocation translateLineCol(FileID FID, unsigned Line, unsigned Col) const; /// \brief If \p Loc points inside a function macro argument, the returned /// location will be the macro location in which the argument was expanded. /// If a macro argument is used multiple times, the expanded location will /// be at the first expansion of the argument. /// e.g. /// MY_MACRO(foo); /// ^ /// Passing a file location pointing at 'foo', will yield a macro location /// where 'foo' was expanded into. SourceLocation getMacroArgExpandedLocation(SourceLocation Loc) const; /// \brief Determines the order of 2 source locations in the translation unit. /// /// \returns true if LHS source location comes before RHS, false otherwise. bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const; /// \brief Determines the order of 2 source locations in the "source location /// address space". bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const { return isBeforeInSLocAddrSpace(LHS, RHS.getOffset()); } /// \brief Determines the order of a source location and a source location /// offset in the "source location address space". /// /// Note that we always consider source locations loaded from bool isBeforeInSLocAddrSpace(SourceLocation LHS, unsigned RHS) const { unsigned LHSOffset = LHS.getOffset(); bool LHSLoaded = LHSOffset >= CurrentLoadedOffset; bool RHSLoaded = RHS >= CurrentLoadedOffset; if (LHSLoaded == RHSLoaded) return LHSOffset < RHS; return LHSLoaded; } // Iterators over FileInfos. typedef llvm::DenseMap ::const_iterator fileinfo_iterator; fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); } fileinfo_iterator fileinfo_end() const { return FileInfos.end(); } bool hasFileInfo(const FileEntry *File) const { return FileInfos.find(File) != FileInfos.end(); } /// \brief Print statistics to stderr. /// void PrintStats() const; void dump() const; /// \brief Get the number of local SLocEntries we have. unsigned local_sloc_entry_size() const { return LocalSLocEntryTable.size(); } /// \brief Get a local SLocEntry. This is exposed for indexing. const SrcMgr::SLocEntry &getLocalSLocEntry(unsigned Index, bool *Invalid = nullptr) const { assert(Index < LocalSLocEntryTable.size() && "Invalid index"); return LocalSLocEntryTable[Index]; } /// \brief Get the number of loaded SLocEntries we have. unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();} /// \brief Get a loaded SLocEntry. This is exposed for indexing. const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index, bool *Invalid = nullptr) const { assert(Index < LoadedSLocEntryTable.size() && "Invalid index"); if (SLocEntryLoaded[Index]) return LoadedSLocEntryTable[Index]; return loadSLocEntry(Index, Invalid); } const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = nullptr) const { if (FID.ID == 0 || FID.ID == -1) { if (Invalid) *Invalid = true; return LocalSLocEntryTable[0]; } return getSLocEntryByID(FID.ID, Invalid); } unsigned getNextLocalOffset() const { return NextLocalOffset; } void setExternalSLocEntrySource(ExternalSLocEntrySource *Source) { assert(LoadedSLocEntryTable.empty() && "Invalidating existing loaded entries"); ExternalSLocEntries = Source; } /// \brief Allocate a number of loaded SLocEntries, which will be actually /// loaded on demand from the external source. /// /// NumSLocEntries will be allocated, which occupy a total of TotalSize space /// in the global source view. The lowest ID and the base offset of the /// entries will be returned. std::pair AllocateLoadedSLocEntries(unsigned NumSLocEntries, unsigned TotalSize); /// \brief Returns true if \p Loc came from a PCH/Module. bool isLoadedSourceLocation(SourceLocation Loc) const { return Loc.getOffset() >= CurrentLoadedOffset; } /// \brief Returns true if \p Loc did not come from a PCH/Module. bool isLocalSourceLocation(SourceLocation Loc) const { return Loc.getOffset() < NextLocalOffset; } /// \brief Returns true if \p FID came from a PCH/Module. bool isLoadedFileID(FileID FID) const { assert(FID.ID != -1 && "Using FileID sentinel value"); return FID.ID < 0; } /// \brief Returns true if \p FID did not come from a PCH/Module. bool isLocalFileID(FileID FID) const { return !isLoadedFileID(FID); } /// Gets the location of the immediate macro caller, one level up the stack /// toward the initial macro typed into the source. SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const { if (!Loc.isMacroID()) return Loc; // When we have the location of (part of) an expanded parameter, its // spelling location points to the argument as expanded in the macro call, // and therefore is used to locate the macro caller. if (isMacroArgExpansion(Loc)) return getImmediateSpellingLoc(Loc); // Otherwise, the caller of the macro is located where this macro is // expanded (while the spelling is part of the macro definition). return getImmediateExpansionRange(Loc).first; } private: llvm::MemoryBuffer *getFakeBufferForRecovery() const; const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const; const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const; /// \brief Get the entry with the given unwrapped FileID. const SrcMgr::SLocEntry &getSLocEntryByID(int ID, bool *Invalid = nullptr) const { assert(ID != -1 && "Using FileID sentinel value"); if (ID < 0) return getLoadedSLocEntryByID(ID, Invalid); return getLocalSLocEntry(static_cast(ID), Invalid); } const SrcMgr::SLocEntry & getLoadedSLocEntryByID(int ID, bool *Invalid = nullptr) const { return getLoadedSLocEntry(static_cast(-ID - 2), Invalid); } /// Implements the common elements of storing an expansion info struct into /// the SLocEntry table and producing a source location that refers to it. SourceLocation createExpansionLocImpl(const SrcMgr::ExpansionInfo &Expansion, unsigned TokLength, int LoadedID = 0, unsigned LoadedOffset = 0); /// \brief Return true if the specified FileID contains the /// specified SourceLocation offset. This is a very hot method. inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const { const SrcMgr::SLocEntry &Entry = getSLocEntry(FID); // If the entry is after the offset, it can't contain it. if (SLocOffset < Entry.getOffset()) return false; // If this is the very last entry then it does. if (FID.ID == -2) return true; // If it is the last local entry, then it does if the location is local. if (FID.ID+1 == static_cast(LocalSLocEntryTable.size())) return SLocOffset < NextLocalOffset; // Otherwise, the entry after it has to not include it. This works for both // local and loaded entries. return SLocOffset < getSLocEntryByID(FID.ID+1).getOffset(); } /// \brief Returns the previous in-order FileID or an invalid FileID if there /// is no previous one. FileID getPreviousFileID(FileID FID) const; /// \brief Returns the next in-order FileID or an invalid FileID if there is /// no next one. FileID getNextFileID(FileID FID) const; /// \brief Create a new fileID for the specified ContentCache and /// include position. /// /// This works regardless of whether the ContentCache corresponds to a /// file or some other input source. FileID createFileID(const SrcMgr::ContentCache* File, SourceLocation IncludePos, SrcMgr::CharacteristicKind DirCharacter, int LoadedID, unsigned LoadedOffset); const SrcMgr::ContentCache * getOrCreateContentCache(const FileEntry *SourceFile, bool isSystemFile = false); /// \brief Create a new ContentCache for the specified memory buffer. const SrcMgr::ContentCache * createMemBufferContentCache(std::unique_ptr Buf); FileID getFileIDSlow(unsigned SLocOffset) const; FileID getFileIDLocal(unsigned SLocOffset) const; FileID getFileIDLoaded(unsigned SLocOffset) const; SourceLocation getExpansionLocSlowCase(SourceLocation Loc) const; SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const; SourceLocation getFileLocSlowCase(SourceLocation Loc) const; std::pair getDecomposedExpansionLocSlowCase(const SrcMgr::SLocEntry *E) const; std::pair getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, unsigned Offset) const; void computeMacroArgsCache(MacroArgsMap &MacroArgsCache, FileID FID) const; void associateFileChunkWithMacroArgExp(MacroArgsMap &MacroArgsCache, FileID FID, SourceLocation SpellLoc, SourceLocation ExpansionLoc, unsigned ExpansionLength) const; friend class ASTReader; friend class ASTWriter; }; /// \brief Comparison function object. template class BeforeThanCompare; /// \brief Compare two source locations. template<> class BeforeThanCompare { SourceManager &SM; public: explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { } bool operator()(SourceLocation LHS, SourceLocation RHS) const { return SM.isBeforeInTranslationUnit(LHS, RHS); } }; /// \brief Compare two non-overlapping source ranges. template<> class BeforeThanCompare { SourceManager &SM; public: explicit BeforeThanCompare(SourceManager &SM) : SM(SM) { } bool operator()(SourceRange LHS, SourceRange RHS) const { return SM.isBeforeInTranslationUnit(LHS.getBegin(), RHS.getBegin()); } }; } // end namespace clang #endif // LLVM_CLANG_BASIC_SOURCEMANAGER_H Index: vendor/clang/dist/include/clang/Frontend/ASTUnit.h =================================================================== --- vendor/clang/dist/include/clang/Frontend/ASTUnit.h (revision 318415) +++ vendor/clang/dist/include/clang/Frontend/ASTUnit.h (revision 318416) @@ -1,920 +1,914 @@ //===--- ASTUnit.h - ASTUnit utility ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // ASTUnit utility class. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H #define LLVM_CLANG_FRONTEND_ASTUNIT_H #include "clang-c/Index.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetOptions.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Serialization/ASTBitCodes.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/MD5.h" #include #include #include #include #include #include namespace llvm { class MemoryBuffer; } namespace clang { class Sema; class ASTContext; class ASTReader; class CompilerInvocation; class CompilerInstance; class Decl; class DiagnosticsEngine; class FileEntry; class FileManager; class HeaderSearch; class MemoryBufferCache; class Preprocessor; class PCHContainerOperations; class PCHContainerReader; class TargetInfo; class FrontendAction; class ASTDeserializationListener; /// \brief Utility class for loading a ASTContext from an AST file. /// class ASTUnit : public ModuleLoader { public: struct StandaloneFixIt { std::pair RemoveRange; std::pair InsertFromRange; std::string CodeToInsert; bool BeforePreviousInsertions; }; struct StandaloneDiagnostic { unsigned ID; DiagnosticsEngine::Level Level; std::string Message; std::string Filename; unsigned LocOffset; std::vector > Ranges; std::vector FixIts; }; private: std::shared_ptr LangOpts; IntrusiveRefCntPtr Diagnostics; IntrusiveRefCntPtr FileMgr; IntrusiveRefCntPtr SourceMgr; IntrusiveRefCntPtr PCMCache; std::unique_ptr HeaderInfo; IntrusiveRefCntPtr Target; std::shared_ptr PP; IntrusiveRefCntPtr Ctx; std::shared_ptr TargetOpts; std::shared_ptr HSOpts; IntrusiveRefCntPtr Reader; bool HadModuleLoaderFatalFailure; struct ASTWriterData; std::unique_ptr WriterData; FileSystemOptions FileSystemOpts; /// \brief The AST consumer that received information about the translation /// unit as it was parsed or loaded. std::unique_ptr Consumer; /// \brief The semantic analysis object used to type-check the translation /// unit. std::unique_ptr TheSema; /// Optional owned invocation, just used to make the invocation used in /// LoadFromCommandLine available. std::shared_ptr Invocation; // OnlyLocalDecls - when true, walking this AST should only visit declarations // that come from the AST itself, not from included precompiled headers. // FIXME: This is temporary; eventually, CIndex will always do this. bool OnlyLocalDecls; /// \brief Whether to capture any diagnostics produced. bool CaptureDiagnostics; /// \brief Track whether the main file was loaded from an AST or not. bool MainFileIsAST; /// \brief What kind of translation unit this AST represents. TranslationUnitKind TUKind; /// \brief Whether we should time each operation. bool WantTiming; /// \brief Whether the ASTUnit should delete the remapped buffers. bool OwnsRemappedFileBuffers; /// Track the top-level decls which appeared in an ASTUnit which was loaded /// from a source file. // // FIXME: This is just an optimization hack to avoid deserializing large parts // of a PCH file when using the Index library on an ASTUnit loaded from // source. In the long term we should make the Index library use efficient and // more scalable search mechanisms. std::vector TopLevelDecls; /// \brief Sorted (by file offset) vector of pairs of file offset/Decl. typedef SmallVector, 64> LocDeclsTy; typedef llvm::DenseMap FileDeclsTy; /// \brief Map from FileID to the file-level declarations that it contains. /// The files and decls are only local (and non-preamble) ones. FileDeclsTy FileDecls; /// The name of the original source file used to generate this ASTUnit. std::string OriginalSourceFile; /// \brief The set of diagnostics produced when creating the preamble. SmallVector PreambleDiagnostics; /// \brief The set of diagnostics produced when creating this /// translation unit. SmallVector StoredDiagnostics; /// \brief The set of diagnostics produced when failing to parse, e.g. due /// to failure to load the PCH. SmallVector FailedParseDiagnostics; /// \brief The number of stored diagnostics that come from the driver /// itself. /// /// Diagnostics that come from the driver are retained from one parse to /// the next. unsigned NumStoredDiagnosticsFromDriver; /// \brief Counter that determines when we want to try building a /// precompiled preamble. /// /// If zero, we will never build a precompiled preamble. Otherwise, /// it's treated as a counter that decrements each time we reparse /// without the benefit of a precompiled preamble. When it hits 1, /// we'll attempt to rebuild the precompiled header. This way, if /// building the precompiled preamble fails, we won't try again for /// some number of calls. unsigned PreambleRebuildCounter; public: class PreambleData { const FileEntry *File; std::vector Buffer; mutable unsigned NumLines; public: PreambleData() : File(nullptr), NumLines(0) { } void assign(const FileEntry *F, const char *begin, const char *end) { File = F; Buffer.assign(begin, end); NumLines = 0; } void clear() { Buffer.clear(); File = nullptr; NumLines = 0; } size_t size() const { return Buffer.size(); } bool empty() const { return Buffer.empty(); } const char *getBufferStart() const { return &Buffer[0]; } unsigned getNumLines() const { if (NumLines) return NumLines; countLines(); return NumLines; } SourceRange getSourceRange(const SourceManager &SM) const { SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID()); return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1)); } private: void countLines() const; }; const PreambleData &getPreambleData() const { return Preamble; } /// Data used to determine if a file used in the preamble has been changed. struct PreambleFileHash { /// All files have size set. off_t Size; /// Modification time is set for files that are on disk. For memory /// buffers it is zero. time_t ModTime; /// Memory buffers have MD5 instead of modification time. We don't /// compute MD5 for on-disk files because we hope that modification time is /// enough to tell if the file was changed. llvm::MD5::MD5Result MD5; static PreambleFileHash createForFile(off_t Size, time_t ModTime); static PreambleFileHash createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); friend bool operator==(const PreambleFileHash &LHS, const PreambleFileHash &RHS); friend bool operator!=(const PreambleFileHash &LHS, const PreambleFileHash &RHS) { return !(LHS == RHS); } }; private: /// \brief The contents of the preamble that has been precompiled to /// \c PreambleFile. PreambleData Preamble; /// \brief Whether the preamble ends at the start of a new line. /// /// Used to inform the lexer as to whether it's starting at the beginning of /// a line after skipping the preamble. bool PreambleEndsAtStartOfLine; /// \brief Keeps track of the files that were used when computing the /// preamble, with both their buffer size and their modification time. /// /// If any of the files have changed from one compile to the next, /// the preamble must be thrown away. llvm::StringMap FilesInPreamble; /// \brief When non-NULL, this is the buffer used to store the contents of /// the main file when it has been padded for use with the precompiled /// preamble. std::unique_ptr SavedMainFileBuffer; /// \brief When non-NULL, this is the buffer used to store the /// contents of the preamble when it has been padded to build the /// precompiled preamble. std::unique_ptr PreambleBuffer; /// \brief The number of warnings that occurred while parsing the preamble. /// /// This value will be used to restore the state of the \c DiagnosticsEngine /// object when re-using the precompiled preamble. Note that only the /// number of warnings matters, since we will not save the preamble /// when any errors are present. unsigned NumWarningsInPreamble; /// \brief A list of the serialization ID numbers for each of the top-level /// declarations parsed within the precompiled preamble. std::vector TopLevelDeclsInPreamble; /// \brief Whether we should be caching code-completion results. bool ShouldCacheCodeCompletionResults : 1; /// \brief Whether to include brief documentation within the set of code /// completions cached. bool IncludeBriefCommentsInCodeCompletion : 1; /// \brief True if non-system source files should be treated as volatile /// (likely to change while trying to use them). bool UserFilesAreVolatile : 1; /// \brief The language options used when we load an AST file. LangOptions ASTFileLangOpts; static void ConfigureDiags(IntrusiveRefCntPtr Diags, ASTUnit &AST, bool CaptureDiagnostics); void TranslateStoredDiagnostics(FileManager &FileMgr, SourceManager &SrcMan, const SmallVectorImpl &Diags, SmallVectorImpl &Out); void clearFileLevelDecls(); public: /// \brief A cached code-completion result, which may be introduced in one of /// many different contexts. struct CachedCodeCompletionResult { /// \brief The code-completion string corresponding to this completion /// result. CodeCompletionString *Completion; /// \brief A bitmask that indicates which code-completion contexts should /// contain this completion result. /// /// The bits in the bitmask correspond to the values of /// CodeCompleteContext::Kind. To map from a completion context kind to a /// bit, shift 1 by that number of bits. Many completions can occur in /// several different contexts. uint64_t ShowInContexts; /// \brief The priority given to this code-completion result. unsigned Priority; /// \brief The libclang cursor kind corresponding to this code-completion /// result. CXCursorKind Kind; /// \brief The availability of this code-completion result. CXAvailabilityKind Availability; /// \brief The simplified type class for a non-macro completion result. SimplifiedTypeClass TypeClass; /// \brief The type of a non-macro completion result, stored as a unique /// integer used by the string map of cached completion types. /// /// This value will be zero if the type is not known, or a unique value /// determined by the formatted type string. Se \c CachedCompletionTypes /// for more information. unsigned Type; }; /// \brief Retrieve the mapping from formatted type names to unique type /// identifiers. llvm::StringMap &getCachedCompletionTypes() { return CachedCompletionTypes; } /// \brief Retrieve the allocator used to cache global code completions. std::shared_ptr getCachedCompletionAllocator() { return CachedCompletionAllocator; } CodeCompletionTUInfo &getCodeCompletionTUInfo() { if (!CCTUInfo) CCTUInfo = llvm::make_unique( std::make_shared()); return *CCTUInfo; } private: /// \brief Allocator used to store cached code completions. std::shared_ptr CachedCompletionAllocator; std::unique_ptr CCTUInfo; /// \brief The set of cached code-completion results. std::vector CachedCompletionResults; /// \brief A mapping from the formatted type name to a unique number for that /// type, which is used for type equality comparisons. llvm::StringMap CachedCompletionTypes; /// \brief A string hash of the top-level declaration and macro definition /// names processed the last time that we reparsed the file. /// /// This hash value is used to determine when we need to refresh the /// global code-completion cache. unsigned CompletionCacheTopLevelHashValue; /// \brief A string hash of the top-level declaration and macro definition /// names processed the last time that we reparsed the precompiled preamble. /// /// This hash value is used to determine when we need to refresh the /// global code-completion cache after a rebuild of the precompiled preamble. unsigned PreambleTopLevelHashValue; /// \brief The current hash value for the top-level declaration and macro /// definition names unsigned CurrentTopLevelHashValue; /// \brief Bit used by CIndex to mark when a translation unit may be in an /// inconsistent state, and is not safe to free. unsigned UnsafeToFree : 1; /// \brief Cache any "global" code-completion results, so that we can avoid /// recomputing them with each completion. void CacheCodeCompletionResults(); /// \brief Clear out and deallocate void ClearCachedCompletionResults(); ASTUnit(const ASTUnit &) = delete; void operator=(const ASTUnit &) = delete; explicit ASTUnit(bool MainFileIsAST); - void CleanTemporaryFiles(); bool Parse(std::shared_ptr PCHContainerOps, std::unique_ptr OverrideMainBuffer); struct ComputedPreamble { llvm::MemoryBuffer *Buffer; std::unique_ptr Owner; unsigned Size; bool PreambleEndsAtStartOfLine; ComputedPreamble(llvm::MemoryBuffer *Buffer, std::unique_ptr Owner, unsigned Size, bool PreambleEndsAtStartOfLine) : Buffer(Buffer), Owner(std::move(Owner)), Size(Size), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} }; ComputedPreamble ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines); std::unique_ptr getMainBufferWithPrecompiledPreamble( std::shared_ptr PCHContainerOps, const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true, unsigned MaxLines = 0); void RealizeTopLevelDeclsFromPreamble(); /// \brief Transfers ownership of the objects (like SourceManager) from /// \param CI to this ASTUnit. void transferASTDataFromCompilerInstance(CompilerInstance &CI); /// \brief Allows us to assert that ASTUnit is not being used concurrently, /// which is not supported. /// /// Clients should create instances of the ConcurrencyCheck class whenever /// using the ASTUnit in a way that isn't intended to be concurrent, which is /// just about any usage. /// Becomes a noop in release mode; only useful for debug mode checking. class ConcurrencyState { void *Mutex; // a llvm::sys::MutexImpl in debug; public: ConcurrencyState(); ~ConcurrencyState(); void start(); void finish(); }; ConcurrencyState ConcurrencyCheckValue; public: class ConcurrencyCheck { ASTUnit &Self; public: explicit ConcurrencyCheck(ASTUnit &Self) : Self(Self) { Self.ConcurrencyCheckValue.start(); } ~ConcurrencyCheck() { Self.ConcurrencyCheckValue.finish(); } }; friend class ConcurrencyCheck; ~ASTUnit() override; bool isMainFileAST() const { return MainFileIsAST; } bool isUnsafeToFree() const { return UnsafeToFree; } void setUnsafeToFree(bool Value) { UnsafeToFree = Value; } const DiagnosticsEngine &getDiagnostics() const { return *Diagnostics; } DiagnosticsEngine &getDiagnostics() { return *Diagnostics; } const SourceManager &getSourceManager() const { return *SourceMgr; } SourceManager &getSourceManager() { return *SourceMgr; } const Preprocessor &getPreprocessor() const { return *PP; } Preprocessor &getPreprocessor() { return *PP; } std::shared_ptr getPreprocessorPtr() const { return PP; } const ASTContext &getASTContext() const { return *Ctx; } ASTContext &getASTContext() { return *Ctx; } void setASTContext(ASTContext *ctx) { Ctx = ctx; } void setPreprocessor(std::shared_ptr pp); bool hasSema() const { return (bool)TheSema; } Sema &getSema() const { assert(TheSema && "ASTUnit does not have a Sema object!"); return *TheSema; } const LangOptions &getLangOpts() const { assert(LangOpts && " ASTUnit does not have language options"); return *LangOpts; } const FileManager &getFileManager() const { return *FileMgr; } FileManager &getFileManager() { return *FileMgr; } const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; } IntrusiveRefCntPtr getASTReader() const; StringRef getOriginalSourceFileName() { return OriginalSourceFile; } ASTMutationListener *getASTMutationListener(); ASTDeserializationListener *getDeserializationListener(); - - /// \brief Add a temporary file that the ASTUnit depends on. - /// - /// This file will be erased when the ASTUnit is destroyed. - void addTemporaryFile(StringRef TempFile); bool getOnlyLocalDecls() const { return OnlyLocalDecls; } bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; } void setOwnsRemappedFileBuffers(bool val) { OwnsRemappedFileBuffers = val; } StringRef getMainFileName() const; /// \brief If this ASTUnit came from an AST file, returns the filename for it. StringRef getASTFileName() const; typedef std::vector::iterator top_level_iterator; top_level_iterator top_level_begin() { assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); if (!TopLevelDeclsInPreamble.empty()) RealizeTopLevelDeclsFromPreamble(); return TopLevelDecls.begin(); } top_level_iterator top_level_end() { assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); if (!TopLevelDeclsInPreamble.empty()) RealizeTopLevelDeclsFromPreamble(); return TopLevelDecls.end(); } std::size_t top_level_size() const { assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); return TopLevelDeclsInPreamble.size() + TopLevelDecls.size(); } bool top_level_empty() const { assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); return TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty(); } /// \brief Add a new top-level declaration. void addTopLevelDecl(Decl *D) { TopLevelDecls.push_back(D); } /// \brief Add a new local file-level declaration. void addFileLevelDecl(Decl *D); /// \brief Get the decls that are contained in a file in the Offset/Length /// range. \p Length can be 0 to indicate a point at \p Offset instead of /// a range. void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length, SmallVectorImpl &Decls); /// \brief Add a new top-level declaration, identified by its ID in /// the precompiled preamble. void addTopLevelDeclFromPreamble(serialization::DeclID D) { TopLevelDeclsInPreamble.push_back(D); } /// \brief Retrieve a reference to the current top-level name hash value. /// /// Note: This is used internally by the top-level tracking action unsigned &getCurrentTopLevelHashValue() { return CurrentTopLevelHashValue; } /// \brief Get the source location for the given file:line:col triplet. /// /// The difference with SourceManager::getLocation is that this method checks /// whether the requested location points inside the precompiled preamble /// in which case the returned source location will be a "loaded" one. SourceLocation getLocation(const FileEntry *File, unsigned Line, unsigned Col) const; /// \brief Get the source location for the given file:offset pair. SourceLocation getLocation(const FileEntry *File, unsigned Offset) const; /// \brief If \p Loc is a loaded location from the preamble, returns /// the corresponding local location of the main file, otherwise it returns /// \p Loc. SourceLocation mapLocationFromPreamble(SourceLocation Loc); /// \brief If \p Loc is a local location of the main file but inside the /// preamble chunk, returns the corresponding loaded location from the /// preamble, otherwise it returns \p Loc. SourceLocation mapLocationToPreamble(SourceLocation Loc); bool isInPreambleFileID(SourceLocation Loc); bool isInMainFileID(SourceLocation Loc); SourceLocation getStartOfMainFileID(); SourceLocation getEndOfPreambleFileID(); /// \see mapLocationFromPreamble. SourceRange mapRangeFromPreamble(SourceRange R) { return SourceRange(mapLocationFromPreamble(R.getBegin()), mapLocationFromPreamble(R.getEnd())); } /// \see mapLocationToPreamble. SourceRange mapRangeToPreamble(SourceRange R) { return SourceRange(mapLocationToPreamble(R.getBegin()), mapLocationToPreamble(R.getEnd())); } // Retrieve the diagnostics associated with this AST typedef StoredDiagnostic *stored_diag_iterator; typedef const StoredDiagnostic *stored_diag_const_iterator; stored_diag_const_iterator stored_diag_begin() const { return StoredDiagnostics.begin(); } stored_diag_iterator stored_diag_begin() { return StoredDiagnostics.begin(); } stored_diag_const_iterator stored_diag_end() const { return StoredDiagnostics.end(); } stored_diag_iterator stored_diag_end() { return StoredDiagnostics.end(); } unsigned stored_diag_size() const { return StoredDiagnostics.size(); } stored_diag_iterator stored_diag_afterDriver_begin() { if (NumStoredDiagnosticsFromDriver > StoredDiagnostics.size()) NumStoredDiagnosticsFromDriver = 0; return StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver; } typedef std::vector::iterator cached_completion_iterator; cached_completion_iterator cached_completion_begin() { return CachedCompletionResults.begin(); } cached_completion_iterator cached_completion_end() { return CachedCompletionResults.end(); } unsigned cached_completion_size() const { return CachedCompletionResults.size(); } /// \brief Returns an iterator range for the local preprocessing entities /// of the local Preprocessor, if this is a parsed source file, or the loaded /// preprocessing entities of the primary module if this is an AST file. llvm::iterator_range getLocalPreprocessingEntities() const; /// \brief Type for a function iterating over a number of declarations. /// \returns true to continue iteration and false to abort. typedef bool (*DeclVisitorFn)(void *context, const Decl *D); /// \brief Iterate over local declarations (locally parsed if this is a parsed /// source file or the loaded declarations of the primary module if this is an /// AST file). /// \returns true if the iteration was complete or false if it was aborted. bool visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn); /// \brief Get the PCH file if one was included. const FileEntry *getPCHFile(); /// \brief Returns true if the ASTUnit was constructed from a serialized /// module file. bool isModuleFile(); std::unique_ptr getBufferForFile(StringRef Filename, std::string *ErrorStr = nullptr); /// \brief Determine what kind of translation unit this AST represents. TranslationUnitKind getTranslationUnitKind() const { return TUKind; } /// \brief A mapping from a file name to the memory buffer that stores the /// remapped contents of that file. typedef std::pair RemappedFile; /// \brief Create a ASTUnit. Gets ownership of the passed CompilerInvocation. static std::unique_ptr create(std::shared_ptr CI, IntrusiveRefCntPtr Diags, bool CaptureDiagnostics, bool UserFilesAreVolatile); /// \brief Create a ASTUnit from an AST file. /// /// \param Filename - The AST file to load. /// /// \param PCHContainerRdr - The PCHContainerOperations to use for loading and /// creating modules. /// \param Diags - The diagnostics engine to use for reporting errors; its /// lifetime is expected to extend past that of the returned ASTUnit. /// /// \returns - The initialized ASTUnit or null if the AST failed to load. static std::unique_ptr LoadFromASTFile( const std::string &Filename, const PCHContainerReader &PCHContainerRdr, IntrusiveRefCntPtr Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo = false, bool OnlyLocalDecls = false, ArrayRef RemappedFiles = None, bool CaptureDiagnostics = false, bool AllowPCHWithCompilerErrors = false, bool UserFilesAreVolatile = false); private: /// \brief Helper function for \c LoadFromCompilerInvocation() and /// \c LoadFromCommandLine(), which loads an AST from a compiler invocation. /// /// \param PrecompilePreambleAfterNParses After how many parses the preamble /// of this translation unit should be precompiled, to improve the performance /// of reparsing. Set to zero to disable preambles. /// /// \returns \c true if a catastrophic failure occurred (which means that the /// \c ASTUnit itself is invalid), or \c false otherwise. bool LoadFromCompilerInvocation( std::shared_ptr PCHContainerOps, unsigned PrecompilePreambleAfterNParses); public: /// \brief Create an ASTUnit from a source file, via a CompilerInvocation /// object, by invoking the optionally provided ASTFrontendAction. /// /// \param CI - The compiler invocation to use; it must have exactly one input /// source file. The ASTUnit takes ownership of the CompilerInvocation object. /// /// \param PCHContainerOps - The PCHContainerOperations to use for loading and /// creating modules. /// /// \param Diags - The diagnostics engine to use for reporting errors; its /// lifetime is expected to extend past that of the returned ASTUnit. /// /// \param Action - The ASTFrontendAction to invoke. Its ownership is not /// transferred. /// /// \param Unit - optionally an already created ASTUnit. Its ownership is not /// transferred. /// /// \param Persistent - if true the returned ASTUnit will be complete. /// false means the caller is only interested in getting info through the /// provided \see Action. /// /// \param ErrAST - If non-null and parsing failed without any AST to return /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit /// mainly to allow the caller to see the diagnostics. /// This will only receive an ASTUnit if a new one was created. If an already /// created ASTUnit was passed in \p Unit then the caller can check that. /// static ASTUnit *LoadFromCompilerInvocationAction( std::shared_ptr CI, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FrontendAction *Action = nullptr, ASTUnit *Unit = nullptr, bool Persistent = true, StringRef ResourceFilesPath = StringRef(), bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, unsigned PrecompilePreambleAfterNParses = 0, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false, std::unique_ptr *ErrAST = nullptr); /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a /// CompilerInvocation object. /// /// \param CI - The compiler invocation to use; it must have exactly one input /// source file. The ASTUnit takes ownership of the CompilerInvocation object. /// /// \param PCHContainerOps - The PCHContainerOperations to use for loading and /// creating modules. /// /// \param Diags - The diagnostics engine to use for reporting errors; its /// lifetime is expected to extend past that of the returned ASTUnit. // // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we // shouldn't need to specify them at construction time. static std::unique_ptr LoadFromCompilerInvocation( std::shared_ptr CI, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FileManager *FileMgr, bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, unsigned PrecompilePreambleAfterNParses = 0, TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false); /// LoadFromCommandLine - Create an ASTUnit from a vector of command line /// arguments, which must specify exactly one source file. /// /// \param ArgBegin - The beginning of the argument vector. /// /// \param ArgEnd - The end of the argument vector. /// /// \param PCHContainerOps - The PCHContainerOperations to use for loading and /// creating modules. /// /// \param Diags - The diagnostics engine to use for reporting errors; its /// lifetime is expected to extend past that of the returned ASTUnit. /// /// \param ResourceFilesPath - The path to the compiler resource files. /// /// \param ModuleFormat - If provided, uses the specific module format. /// /// \param ErrAST - If non-null and parsing failed without any AST to return /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit /// mainly to allow the caller to see the diagnostics. /// // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we // shouldn't need to specify them at construction time. static ASTUnit *LoadFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, ArrayRef RemappedFiles = None, bool RemappedFilesKeepOriginalName = true, unsigned PrecompilePreambleAfterNParses = 0, TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false, bool UserFilesAreVolatile = false, bool ForSerialization = false, llvm::Optional ModuleFormat = llvm::None, std::unique_ptr *ErrAST = nullptr); /// \brief Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. /// /// \returns True if a failure occurred that causes the ASTUnit not to /// contain any translation-unit information, false otherwise. bool Reparse(std::shared_ptr PCHContainerOps, ArrayRef RemappedFiles = None); /// \brief Perform code completion at the given file, line, and /// column within this translation unit. /// /// \param File The file in which code completion will occur. /// /// \param Line The line at which code completion will occur. /// /// \param Column The column at which code completion will occur. /// /// \param IncludeMacros Whether to include macros in the code-completion /// results. /// /// \param IncludeCodePatterns Whether to include code patterns (such as a /// for loop) in the code-completion results. /// /// \param IncludeBriefComments Whether to include brief documentation within /// the set of code completions returned. /// /// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, StoredDiagnostics, and /// OwnedBuffers parameters are all disgusting hacks. They will go away. void CodeComplete(StringRef File, unsigned Line, unsigned Column, ArrayRef RemappedFiles, bool IncludeMacros, bool IncludeCodePatterns, bool IncludeBriefComments, CodeCompleteConsumer &Consumer, std::shared_ptr PCHContainerOps, DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, SmallVectorImpl &StoredDiagnostics, SmallVectorImpl &OwnedBuffers); /// \brief Save this translation unit to a file with the given name. /// /// \returns true if there was a file error or false if the save was /// successful. bool Save(StringRef File); /// \brief Serialize this translation unit with the given output stream. /// /// \returns True if an error occurred, false otherwise. bool serialize(raw_ostream &OS); ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) override { // ASTUnit doesn't know how to load modules (not that this matters). return ModuleLoadResult(); } void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, SourceLocation ImportLoc) override {} GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override { return nullptr; } bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override { return 0; } }; } // namespace clang #endif Index: vendor/clang/dist/include/clang/Sema/Sema.h =================================================================== --- vendor/clang/dist/include/clang/Sema/Sema.h (revision 318415) +++ vendor/clang/dist/include/clang/Sema/Sema.h (revision 318416) @@ -1,10489 +1,10487 @@ //===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the Sema class, which performs semantic analysis and // builds ASTs. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_SEMA_H #define LLVM_CLANG_SEMA_SEMA_H #include "clang/AST/Attr.h" #include "clang/AST/Availability.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LocInfoType.h" #include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/CleanupInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include #include #include #include namespace llvm { class APSInt; template struct DenseMapInfo; template class DenseSet; class SmallBitVector; class InlineAsmIdentifierInfo; } namespace clang { class ADLResult; class ASTConsumer; class ASTContext; class ASTMutationListener; class ASTReader; class ASTWriter; class ArrayType; class AttributeList; class BindingDecl; class BlockDecl; class CapturedDecl; class CXXBasePath; class CXXBasePaths; class CXXBindTemporaryExpr; typedef SmallVector CXXCastPath; class CXXConstructorDecl; class CXXConversionDecl; class CXXDeleteExpr; class CXXDestructorDecl; class CXXFieldCollector; class CXXMemberCallExpr; class CXXMethodDecl; class CXXScopeSpec; class CXXTemporary; class CXXTryStmt; class CallExpr; class ClassTemplateDecl; class ClassTemplatePartialSpecializationDecl; class ClassTemplateSpecializationDecl; class VarTemplatePartialSpecializationDecl; class CodeCompleteConsumer; class CodeCompletionAllocator; class CodeCompletionTUInfo; class CodeCompletionResult; class CoroutineBodyStmt; class Decl; class DeclAccessPair; class DeclContext; class DeclRefExpr; class DeclaratorDecl; class DeducedTemplateArgument; class DependentDiagnostic; class DesignatedInitExpr; class Designation; class EnableIfAttr; class EnumConstantDecl; class Expr; class ExtVectorType; class FormatAttr; class FriendDecl; class FunctionDecl; class FunctionProtoType; class FunctionTemplateDecl; class ImplicitConversionSequence; typedef MutableArrayRef ConversionSequenceList; class InitListExpr; class InitializationKind; class InitializationSequence; class InitializedEntity; class IntegerLiteral; class LabelStmt; class LambdaExpr; class LangOptions; class LocalInstantiationScope; class LookupResult; class MacroInfo; typedef ArrayRef> ModuleIdPath; class ModuleLoader; class MultiLevelTemplateArgumentList; class NamedDecl; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCCompatibleAliasDecl; class ObjCContainerDecl; class ObjCImplDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; class ObjCIvarDecl; template class ObjCList; class ObjCMessageExpr; class ObjCMethodDecl; class ObjCPropertyDecl; class ObjCProtocolDecl; class OMPThreadPrivateDecl; class OMPDeclareReductionDecl; class OMPDeclareSimdDecl; class OMPClause; struct OverloadCandidate; class OverloadCandidateSet; class OverloadExpr; class ParenListExpr; class ParmVarDecl; class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; class StandardConversionSequence; class Stmt; class StringLiteral; class SwitchStmt; class TemplateArgument; class TemplateArgumentList; class TemplateArgumentLoc; class TemplateDecl; class TemplateParameterList; class TemplatePartialOrderingContext; class TemplateTemplateParmDecl; class Token; class TypeAliasDecl; class TypedefDecl; class TypedefNameDecl; class TypeLoc; class TypoCorrectionConsumer; class UnqualifiedId; class UnresolvedLookupExpr; class UnresolvedMemberExpr; class UnresolvedSetImpl; class UnresolvedSetIterator; class UsingDecl; class UsingShadowDecl; class ValueDecl; class VarDecl; class VarTemplateSpecializationDecl; class VisibilityAttr; class VisibleDeclConsumer; class IndirectFieldDecl; struct DeductionFailureInfo; class TemplateSpecCandidateSet; namespace sema { class AccessedEntity; class BlockScopeInfo; class CapturedRegionScopeInfo; class CapturingScopeInfo; class CompoundScopeInfo; class DelayedDiagnostic; class DelayedDiagnosticPool; class FunctionScopeInfo; class LambdaScopeInfo; class PossiblyUnreachableDiag; class TemplateDeductionInfo; } namespace threadSafety { class BeforeSet; void threadSafetyCleanup(BeforeSet* Cache); } // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. typedef std::pair, SourceLocation> UnexpandedParameterPack; /// Describes whether we've seen any nullability information for the given /// file. struct FileNullability { /// The first pointer declarator (of any pointer kind) in the file that does /// not have a corresponding nullability annotation. SourceLocation PointerLoc; /// Which kind of pointer declarator we saw. uint8_t PointerKind; /// Whether we saw any type nullability annotations in the given file. bool SawTypeNullability = false; }; /// A mapping from file IDs to a record of whether we've seen nullability /// information in that file. class FileNullabilityMap { /// A mapping from file IDs to the nullability information for each file ID. llvm::DenseMap Map; /// A single-element cache based on the file ID. struct { FileID File; FileNullability Nullability; } Cache; public: FileNullability &operator[](FileID file) { // Check the single-element cache. if (file == Cache.File) return Cache.Nullability; // It's not in the single-element cache; flush the cache if we have one. if (!Cache.File.isInvalid()) { Map[Cache.File] = Cache.Nullability; } // Pull this entry into the cache. Cache.File = file; Cache.Nullability = Map[file]; return Cache.Nullability; } }; /// Sema - This implements semantic analysis and AST building for C. class Sema { Sema(const Sema &) = delete; void operator=(const Sema &) = delete; ///\brief Source of additional semantic information. ExternalSemaSource *ExternalSource; ///\brief Whether Sema has generated a multiplexer and has to delete it. bool isMultiplexExternalSource; static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); bool isVisibleSlow(const NamedDecl *D); bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, const NamedDecl *New) { // We are about to link these. It is now safe to compute the linkage of // the new decl. If the new decl has external linkage, we will // link it with the hidden decl (which also has external linkage) and // it will keep having external linkage. If it has internal linkage, we // will not link it. Since it has no previous decls, it will remain // with internal linkage. return isVisible(Old) || New->isExternallyVisible(); } bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); public: typedef OpaquePtr DeclGroupPtrTy; typedef OpaquePtr TemplateTy; typedef OpaquePtr TypeTy; OpenCLOptions OpenCLFeatures; FPOptions FPFeatures; const LangOptions &LangOpts; Preprocessor &PP; ASTContext &Context; ASTConsumer &Consumer; DiagnosticsEngine &Diags; SourceManager &SourceMgr; /// \brief Flag indicating whether or not to collect detailed statistics. bool CollectStats; /// \brief Code-completion consumer. CodeCompleteConsumer *CodeCompleter; /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; /// \brief Generally null except when we temporarily switch decl contexts, /// like in \see ActOnObjCTemporaryExitContainerContext. DeclContext *OriginalLexicalContext; /// VAListTagName - The declaration name corresponding to __va_list_tag. /// This is used as part of a hack to omit that class from ADL results. DeclarationName VAListTagName; bool MSStructPragmaOn; // True when \#pragma ms_struct on /// \brief Controls member pointer representation format under the MS ABI. LangOptions::PragmaMSPointersToMembersKind MSPointerToMemberRepresentationMethod; /// Stack of active SEH __finally scopes. Can be empty. SmallVector CurrentSEHFinally; /// \brief Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; enum PragmaMsStackAction { PSK_Reset = 0x0, // #pragma () PSK_Set = 0x1, // #pragma (value) PSK_Push = 0x2, // #pragma (push[, id]) PSK_Pop = 0x4, // #pragma (pop[, id]) PSK_Show = 0x8, // #pragma (show) -- only for "pack"! PSK_Push_Set = PSK_Push | PSK_Set, // #pragma (push[, id], value) PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value) }; template struct PragmaStack { struct Slot { llvm::StringRef StackSlotLabel; ValueType Value; SourceLocation PragmaLocation; Slot(llvm::StringRef StackSlotLabel, ValueType Value, SourceLocation PragmaLocation) : StackSlotLabel(StackSlotLabel), Value(Value), PragmaLocation(PragmaLocation) {} }; void Act(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, ValueType Value); // MSVC seems to add artificial slots to #pragma stacks on entering a C++ // method body to restore the stacks on exit, so it works like this: // // struct S { // #pragma (push, InternalPragmaSlot, ) // void Method {} // #pragma (pop, InternalPragmaSlot) // }; // // It works even with #pragma vtordisp, although MSVC doesn't support // #pragma vtordisp(push [, id], n) // syntax. // // Push / pop a named sentinel slot. void SentinelAction(PragmaMsStackAction Action, StringRef Label) { assert((Action == PSK_Push || Action == PSK_Pop) && "Can only push / pop #pragma stack sentinels!"); Act(CurrentPragmaLocation, Action, Label, CurrentValue); } // Constructors. explicit PragmaStack(const ValueType &Default) : DefaultValue(Default), CurrentValue(Default) {} SmallVector Stack; ValueType DefaultValue; // Value used for PSK_Reset action. ValueType CurrentValue; SourceLocation CurrentPragmaLocation; }; // FIXME: We should serialize / deserialize these if they occur in a PCH (but // we shouldn't do so if they're in a module). /// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft /// C++ ABI. Possible values are 0, 1, and 2, which mean: /// /// 0: Suppress all vtordisps /// 1: Insert vtordisps in the presence of vbase overrides and non-trivial /// structors /// 2: Always insert vtordisps to support RTTI on partially constructed /// objects PragmaStack VtorDispStack; // #pragma pack. // Sentinel to represent when the stack is set to mac68k alignment. static const unsigned kMac68kAlignmentSentinel = ~0U; PragmaStack PackStack; // Segment #pragmas. PragmaStack DataSegStack; PragmaStack BSSSegStack; PragmaStack ConstSegStack; PragmaStack CodeSegStack; // RAII object to push / pop sentinel slots for all MS #pragma stacks. // Actions should be performed only if we enter / exit a C++ method body. class PragmaStackSentinelRAII { public: PragmaStackSentinelRAII(Sema &S, StringRef SlotLabel, bool ShouldAct); ~PragmaStackSentinelRAII(); private: Sema &S; StringRef SlotLabel; bool ShouldAct; }; /// A mapping that describes the nullability we've seen in each header file. FileNullabilityMap NullabilityMap; /// Last section used with #pragma init_seg. StringLiteral *CurInitSeg; SourceLocation CurInitSegLoc; /// VisContext - Manages the stack for \#pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" /// \brief This represents the stack of attributes that were pushed by /// \#pragma clang attribute. struct PragmaAttributeEntry { SourceLocation Loc; AttributeList *Attribute; SmallVector MatchRules; bool IsUsed; }; SmallVector PragmaAttributeStack; /// \brief The declaration that is currently receiving an attribute from the /// #pragma attribute stack. const Decl *PragmaAttributeCurrentTargetDecl; /// \brief This represents the last location of a "#pragma clang optimize off" /// directive if such a directive has not been closed by an "on" yet. If /// optimizations are currently "on", this is set to an invalid location. SourceLocation OptimizeOffPragmaLocation; /// \brief Flag indicating if Sema is building a recovery call expression. /// /// This flag is used to avoid building recovery call expressions /// if Sema is already doing so, which would cause infinite recursions. bool IsBuildingRecoveryCallExpr; /// Used to control the generation of ExprWithCleanups. CleanupInfo Cleanup; /// ExprCleanupObjects - This is the stack of objects requiring /// cleanup that are created by the current full expression. The /// element type here is ExprWithCleanups::Object. SmallVector ExprCleanupObjects; /// \brief Store a list of either DeclRefExprs or MemberExprs /// that contain a reference to a variable (constant) that may or may not /// be odr-used in this Expr, and we won't know until all lvalue-to-rvalue /// and discarded value conversions have been applied to all subexpressions /// of the enclosing full expression. This is cleared at the end of each /// full expression. llvm::SmallPtrSet MaybeODRUseExprs; /// \brief Stack containing information about each of the nested /// function, block, and method scopes that are currently active. /// /// This array is never empty. Clients should ignore the first /// element, which is used to cache a single FunctionScopeInfo /// that's used to parse every top-level function. SmallVector FunctionScopes; typedef LazyVector ExtVectorDeclsType; /// ExtVectorDecls - This is a list all the extended vector types. This allows /// us to associate a raw vector type with one of the ext_vector type names. /// This is only necessary for issuing pretty diagnostics. ExtVectorDeclsType ExtVectorDecls; /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. std::unique_ptr FieldCollector; typedef llvm::SmallSetVector NamedDeclSetType; /// \brief Set containing all declared private fields that are not used. NamedDeclSetType UnusedPrivateFields; /// \brief Set containing all typedefs that are likely unused. llvm::SmallSetVector UnusedLocalTypedefNameCandidates; /// \brief Delete-expressions to be analyzed at the end of translation unit /// /// This list contains class members, and locations of delete-expressions /// that could not be proven as to whether they mismatch with new-expression /// used in initializer of the field. typedef std::pair DeleteExprLoc; typedef llvm::SmallVector DeleteLocs; llvm::MapVector DeleteExprs; typedef llvm::SmallPtrSet RecordDeclSetTy; /// PureVirtualClassDiagSet - a set of class declarations which we have /// emitted a list of pure virtual functions. Used to prevent emitting the /// same list more than once. std::unique_ptr PureVirtualClassDiagSet; /// ParsingInitForAutoVars - a set of declarations with auto types for which /// we are currently parsing the initializer. llvm::SmallPtrSet ParsingInitForAutoVars; /// \brief Look for a locally scoped extern "C" declaration by the given name. NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); typedef LazyVector TentativeDefinitionsType; /// \brief All the tentative definitions encountered in the TU. TentativeDefinitionsType TentativeDefinitions; typedef LazyVector UnusedFileScopedDeclsType; /// \brief The set of file scoped decls seen so far that have not been used /// and must warn if not used. Only contains the first declaration. UnusedFileScopedDeclsType UnusedFileScopedDecls; typedef LazyVector DelegatingCtorDeclsType; /// \brief All the delegating constructors seen so far in the file, used for /// cycle detection at the end of the TU. DelegatingCtorDeclsType DelegatingCtorDecls; /// \brief All the overriding functions seen during a class definition /// that had their exception spec checks delayed, plus the overridden /// function. SmallVector, 2> DelayedExceptionSpecChecks; /// \brief All the members seen during a class definition which were both /// explicitly defaulted and had explicitly-specified exception /// specifications, along with the function type containing their /// user-specified exception specification. Those exception specifications /// were overridden with the default specifications, but we still need to /// check whether they are compatible with the default specification, and /// we can't do that until the nesting set of class definitions is complete. SmallVector, 2> DelayedDefaultedMemberExceptionSpecs; typedef llvm::MapVector> LateParsedTemplateMapT; LateParsedTemplateMapT LateParsedTemplateMap; /// \brief Callback to the parser to parse templated functions when needed. typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT); typedef void LateTemplateParserCleanupCB(void *P); LateTemplateParserCB *LateTemplateParser; LateTemplateParserCleanupCB *LateTemplateParserCleanup; void *OpaqueParser; void SetLateTemplateParser(LateTemplateParserCB *LTP, LateTemplateParserCleanupCB *LTPCleanup, void *P) { LateTemplateParser = LTP; LateTemplateParserCleanup = LTPCleanup; OpaqueParser = P; } class DelayedDiagnostics; class DelayedDiagnosticsState { sema::DelayedDiagnosticPool *SavedPool; friend class Sema::DelayedDiagnostics; }; typedef DelayedDiagnosticsState ParsingDeclState; typedef DelayedDiagnosticsState ProcessingContextState; /// A class which encapsulates the logic for delaying diagnostics /// during parsing and other processing. class DelayedDiagnostics { /// \brief The current pool of diagnostics into which delayed /// diagnostics should go. sema::DelayedDiagnosticPool *CurPool; public: DelayedDiagnostics() : CurPool(nullptr) {} /// Adds a delayed diagnostic. void add(const sema::DelayedDiagnostic &diag); // in DelayedDiagnostic.h /// Determines whether diagnostics should be delayed. bool shouldDelayDiagnostics() { return CurPool != nullptr; } /// Returns the current delayed-diagnostics pool. sema::DelayedDiagnosticPool *getCurrentPool() const { return CurPool; } /// Enter a new scope. Access and deprecation diagnostics will be /// collected in this pool. DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) { DelayedDiagnosticsState state; state.SavedPool = CurPool; CurPool = &pool; return state; } /// Leave a delayed-diagnostic state that was previously pushed. /// Do not emit any of the diagnostics. This is performed as part /// of the bookkeeping of popping a pool "properly". void popWithoutEmitting(DelayedDiagnosticsState state) { CurPool = state.SavedPool; } /// Enter a new scope where access and deprecation diagnostics are /// not delayed. DelayedDiagnosticsState pushUndelayed() { DelayedDiagnosticsState state; state.SavedPool = CurPool; CurPool = nullptr; return state; } /// Undo a previous pushUndelayed(). void popUndelayed(DelayedDiagnosticsState state) { assert(CurPool == nullptr); CurPool = state.SavedPool; } } DelayedDiagnostics; /// A RAII object to temporarily push a declaration context. class ContextRAII { private: Sema &S; DeclContext *SavedContext; ProcessingContextState SavedContextState; QualType SavedCXXThisTypeOverride; public: ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true) : S(S), SavedContext(S.CurContext), SavedContextState(S.DelayedDiagnostics.pushUndelayed()), SavedCXXThisTypeOverride(S.CXXThisTypeOverride) { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; if (NewThisContext) S.CXXThisTypeOverride = QualType(); } void pop() { if (!SavedContext) return; S.CurContext = SavedContext; S.DelayedDiagnostics.popUndelayed(SavedContextState); S.CXXThisTypeOverride = SavedCXXThisTypeOverride; SavedContext = nullptr; } ~ContextRAII() { pop(); } }; /// \brief RAII object to handle the state changes required to synthesize /// a function body. class SynthesizedFunctionScope { Sema &S; Sema::ContextRAII SavedContext; public: SynthesizedFunctionScope(Sema &S, DeclContext *DC) : S(S), SavedContext(S, DC) { S.PushFunctionScope(); S.PushExpressionEvaluationContext( Sema::ExpressionEvaluationContext::PotentiallyEvaluated); } ~SynthesizedFunctionScope() { S.PopExpressionEvaluationContext(); S.PopFunctionScopeInfo(); } }; /// WeakUndeclaredIdentifiers - Identifiers contained in /// \#pragma weak before declared. rare. may alias another /// identifier, declared or undeclared llvm::MapVector WeakUndeclaredIdentifiers; /// ExtnameUndeclaredIdentifiers - Identifiers contained in /// \#pragma redefine_extname before declared. Used in Solaris system headers /// to define functions that occur in multiple standards to call the version /// in the currently selected standard. llvm::DenseMap ExtnameUndeclaredIdentifiers; /// \brief Load weak undeclared identifiers from the external source. void LoadExternalWeakUndeclaredIdentifiers(); /// WeakTopLevelDecl - Translation-unit scoped declarations generated by /// \#pragma weak during processing of other Decls. /// I couldn't figure out a clean way to generate these in-line, so /// we store them here and handle separately -- which is a hack. /// It would be best to refactor this. SmallVector WeakTopLevelDecl; IdentifierResolver IdResolver; /// Translation Unit Scope - useful to Objective-C actions that need /// to lookup file scope declarations in the "ordinary" C decl namespace. /// For example, user-defined classes, built-in "id" type, etc. Scope *TUScope; /// \brief The C++ "std" namespace, where the standard library resides. LazyDeclPtr StdNamespace; /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. LazyDeclPtr StdBadAlloc; /// \brief The C++ "std::align_val_t" enum class, which is defined by the C++ /// standard library. LazyDeclPtr StdAlignValT; /// \brief The C++ "std::experimental" namespace, where the experimental parts /// of the standard library resides. NamespaceDecl *StdExperimentalNamespaceCache; /// \brief The C++ "std::initializer_list" template, which is defined in /// \. ClassTemplateDecl *StdInitializerList; /// \brief The C++ "type_info" declaration, which is defined in \. RecordDecl *CXXTypeInfoDecl; /// \brief The MSVC "_GUID" struct, which is defined in MSVC header files. RecordDecl *MSVCGuidDecl; /// \brief Caches identifiers/selectors for NSFoundation APIs. std::unique_ptr NSAPIObj; /// \brief The declaration of the Objective-C NSNumber class. ObjCInterfaceDecl *NSNumberDecl; /// \brief The declaration of the Objective-C NSValue class. ObjCInterfaceDecl *NSValueDecl; /// \brief Pointer to NSNumber type (NSNumber *). QualType NSNumberPointer; /// \brief Pointer to NSValue type (NSValue *). QualType NSValuePointer; /// \brief The Objective-C NSNumber methods used to create NSNumber literals. ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; /// \brief The declaration of the Objective-C NSString class. ObjCInterfaceDecl *NSStringDecl; /// \brief Pointer to NSString type (NSString *). QualType NSStringPointer; /// \brief The declaration of the stringWithUTF8String: method. ObjCMethodDecl *StringWithUTF8StringMethod; /// \brief The declaration of the valueWithBytes:objCType: method. ObjCMethodDecl *ValueWithBytesObjCTypeMethod; /// \brief The declaration of the Objective-C NSArray class. ObjCInterfaceDecl *NSArrayDecl; /// \brief The declaration of the arrayWithObjects:count: method. ObjCMethodDecl *ArrayWithObjectsMethod; /// \brief The declaration of the Objective-C NSDictionary class. ObjCInterfaceDecl *NSDictionaryDecl; /// \brief The declaration of the dictionaryWithObjects:forKeys:count: method. ObjCMethodDecl *DictionaryWithObjectsMethod; /// \brief id type. QualType QIDNSCopying; /// \brief will hold 'respondsToSelector:' Selector RespondsToSelectorSel; /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; /// A flag to indicate that we're in a context that permits abstract /// references to fields. This is really a bool AllowAbstractFieldReference; /// \brief Describes how the expressions currently being parsed are /// evaluated at run-time, if at all. enum class ExpressionEvaluationContext { /// \brief The current expression and its subexpressions occur within an /// unevaluated operand (C++11 [expr]p7), such as the subexpression of /// \c sizeof, where the type of the expression may be significant but /// no code will be generated to evaluate the value of the expression at /// run time. Unevaluated, /// \brief The current expression occurs within a braced-init-list within /// an unevaluated operand. This is mostly like a regular unevaluated /// context, except that we still instantiate constexpr functions that are /// referenced here so that we can perform narrowing checks correctly. UnevaluatedList, /// \brief The current expression occurs within a discarded statement. /// This behaves largely similarly to an unevaluated operand in preventing /// definitions from being required, but not in other ways. DiscardedStatement, /// \brief The current expression occurs within an unevaluated /// operand that unconditionally permits abstract references to /// fields, such as a SIZE operator in MS-style inline assembly. UnevaluatedAbstract, /// \brief The current context is "potentially evaluated" in C++11 terms, /// but the expression is evaluated at compile-time (like the values of /// cases in a switch statement). ConstantEvaluated, /// \brief The current expression is potentially evaluated at run time, /// which means that code may be generated to evaluate the value of the /// expression at run time. PotentiallyEvaluated, /// \brief The current expression is potentially evaluated, but any /// declarations referenced inside that expression are only used if /// in fact the current expression is used. /// /// This value is used when parsing default function arguments, for which /// we would like to provide diagnostics (e.g., passing non-POD arguments /// through varargs) but do not want to mark declarations as "referenced" /// until the default argument is used. PotentiallyEvaluatedIfUsed }; /// \brief Data structure used to record current or nested /// expression evaluation contexts. struct ExpressionEvaluationContextRecord { /// \brief The expression evaluation context. ExpressionEvaluationContext Context; /// \brief Whether the enclosing context needed a cleanup. CleanupInfo ParentCleanup; /// \brief Whether we are in a decltype expression. bool IsDecltype; /// \brief The number of active cleanup objects when we entered /// this expression evaluation context. unsigned NumCleanupObjects; /// \brief The number of typos encountered during this expression evaluation /// context (i.e. the number of TypoExprs created). unsigned NumTypos; llvm::SmallPtrSet SavedMaybeODRUseExprs; /// \brief The lambdas that are present within this context, if it /// is indeed an unevaluated context. SmallVector Lambdas; /// \brief The declaration that provides context for lambda expressions /// and block literals if the normal declaration context does not /// suffice, e.g., in a default function argument. Decl *ManglingContextDecl; /// \brief The context information used to mangle lambda expressions /// and block literals within this context. /// /// This mangling information is allocated lazily, since most contexts /// do not have lambda expressions or block literals. std::unique_ptr MangleNumbering; /// \brief If we are processing a decltype type, a set of call expressions /// for which we have deferred checking the completeness of the return type. SmallVector DelayedDecltypeCalls; /// \brief If we are processing a decltype type, a set of temporary binding /// expressions for which we have deferred checking the destructor. SmallVector DelayedDecltypeBinds; ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, bool IsDecltype) : Context(Context), ParentCleanup(ParentCleanup), IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), NumTypos(0), ManglingContextDecl(ManglingContextDecl), MangleNumbering() { } /// \brief Retrieve the mangling numbering context, used to consistently /// number constructs like lambdas for mangling. MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx); bool isUnevaluated() const { return Context == ExpressionEvaluationContext::Unevaluated || Context == ExpressionEvaluationContext::UnevaluatedAbstract || Context == ExpressionEvaluationContext::UnevaluatedList; } bool isConstantEvaluated() const { return Context == ExpressionEvaluationContext::ConstantEvaluated; } }; /// A stack of expression evaluation contexts. SmallVector ExprEvalContexts; /// \brief Compute the mangling number context for a lambda expression or /// block literal. /// /// \param DC - The DeclContext containing the lambda expression or /// block literal. /// \param[out] ManglingContextDecl - Returns the ManglingContextDecl /// associated with the context, if relevant. MangleNumberingContext *getCurrentMangleNumberContext( const DeclContext *DC, Decl *&ManglingContextDecl); /// SpecialMemberOverloadResult - The overloading result for a special member /// function. /// /// This is basically a wrapper around PointerIntPair. The lowest bits of the /// integer are used to determine whether overload resolution succeeded. class SpecialMemberOverloadResult { public: enum Kind { NoMemberOrDeleted, Ambiguous, Success }; private: llvm::PointerIntPair Pair; public: SpecialMemberOverloadResult() : Pair() {} SpecialMemberOverloadResult(CXXMethodDecl *MD) : Pair(MD, MD->isDeleted() ? NoMemberOrDeleted : Success) {} CXXMethodDecl *getMethod() const { return Pair.getPointer(); } void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } Kind getKind() const { return static_cast(Pair.getInt()); } void setKind(Kind K) { Pair.setInt(K); } }; class SpecialMemberOverloadResultEntry : public llvm::FastFoldingSetNode, public SpecialMemberOverloadResult { public: SpecialMemberOverloadResultEntry(const llvm::FoldingSetNodeID &ID) : FastFoldingSetNode(ID) {} }; /// \brief A cache of special member function overload resolution results /// for C++ records. llvm::FoldingSet SpecialMemberCache; /// \brief A cache of the flags available in enumerations with the flag_bits /// attribute. mutable llvm::DenseMap FlagBitsCache; /// \brief The kind of translation unit we are processing. /// /// When we're processing a complete translation unit, Sema will perform /// end-of-translation-unit semantic tasks (such as creating /// initializers for tentative definitions in C) once parsing has /// completed. Modules and precompiled headers perform different kinds of /// checks. TranslationUnitKind TUKind; llvm::BumpPtrAllocator BumpAlloc; /// \brief The number of SFINAE diagnostics that have been trapped. unsigned NumSFINAEErrors; typedef llvm::DenseMap> UnparsedDefaultArgInstantiationsMap; /// \brief A mapping from parameters with unparsed default arguments to the /// set of instantiations of each parameter. /// /// This mapping is a temporary data structure used when parsing /// nested class templates or nested classes of class templates, /// where we might end up instantiating an inner class before the /// default arguments of its methods have been parsed. UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations; // Contains the locations of the beginning of unparsed default // argument locations. llvm::DenseMap UnparsedDefaultArgLocs; /// UndefinedInternals - all the used, undefined objects which require a /// definition in this translation unit. llvm::MapVector UndefinedButUsed; /// Obtain a sorted list of functions that are undefined but ODR-used. void getUndefinedButUsed( SmallVectorImpl > &Undefined); /// Retrieves list of suspicious delete-expressions that will be checked at /// the end of translation unit. const llvm::MapVector & getMismatchingDeleteExpressions() const; typedef std::pair GlobalMethods; typedef llvm::DenseMap GlobalMethodPool; /// Method Pool - allows efficient lookup when typechecking messages to "id". /// We need to maintain a list, since selectors can have differing signatures /// across classes. In Cocoa, this happens to be extremely uncommon (only 1% /// of selectors are "overloaded"). /// At the head of the list it is recorded whether there were 0, 1, or >= 2 /// methods inside categories with a particular selector. GlobalMethodPool MethodPool; /// Method selectors used in a \@selector expression. Used for implementation /// of -Wselector. llvm::MapVector ReferencedSelectors; /// Kinds of C++ special members. enum CXXSpecialMember { CXXDefaultConstructor, CXXCopyConstructor, CXXMoveConstructor, CXXCopyAssignment, CXXMoveAssignment, CXXDestructor, CXXInvalid }; typedef std::pair SpecialMemberDecl; /// The C++ special members which we are currently in the process of /// declaring. If this process recursively triggers the declaration of the /// same special member, we should act as if it is not yet declared. llvm::SmallSet SpecialMembersBeingDeclared; /// The function definitions which were renamed as part of typo-correction /// to match their respective declarations. We want to keep track of them /// to ensure that we don't emit a "redefinition" error if we encounter a /// correctly named definition after the renamed definition. llvm::SmallPtrSet TypoCorrectedFunctionDefinitions; /// Stack of types that correspond to the parameter entities that are /// currently being copy-initialized. Can be empty. llvm::SmallVector CurrentParameterCopyTypes; void ReadMethodPool(Selector Sel); void updateOutOfDateSelector(Selector Sel); /// Private Helper predicate to check for 'self'. bool isSelfExpr(Expr *RExpr); bool isSelfExpr(Expr *RExpr, const ObjCMethodDecl *Method); /// \brief Cause the active diagnostic on the DiagosticsEngine to be /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and /// should not be used elsewhere. void EmitCurrentDiagnostic(unsigned DiagID); /// Records and restores the FP_CONTRACT state on entry/exit of compound /// statements. class FPContractStateRAII { public: FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {} ~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; } private: Sema& S; FPOptions OldFPFeaturesState; }; void addImplicitTypedef(StringRef Name, QualType T); public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind = TU_Complete, CodeCompleteConsumer *CompletionConsumer = nullptr); ~Sema(); /// \brief Perform initialization that occurs after the parser has been /// initialized but before it parses anything. void Initialize(); const LangOptions &getLangOpts() const { return LangOpts; } OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } FPOptions &getFPOptions() { return FPFeatures; } DiagnosticsEngine &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } Preprocessor &getPreprocessor() const { return PP; } ASTContext &getASTContext() const { return Context; } ASTConsumer &getASTConsumer() const { return Consumer; } ASTMutationListener *getASTMutationListener() const; ExternalSemaSource* getExternalSource() const { return ExternalSource; } ///\brief Registers an external source. If an external source already exists, /// creates a multiplex external source and appends to it. /// ///\param[in] E - A non-null external sema source. /// void addExternalSource(ExternalSemaSource *E); void PrintStats() const; /// \brief Helper class that creates diagnostics with optional /// template instantiation stacks. /// /// This class provides a wrapper around the basic DiagnosticBuilder /// class that emits diagnostics. SemaDiagnosticBuilder is /// responsible for emitting the diagnostic (as DiagnosticBuilder /// does) and, if the diagnostic comes from inside a template /// instantiation, printing the template instantiation stack as /// well. class SemaDiagnosticBuilder : public DiagnosticBuilder { Sema &SemaRef; unsigned DiagID; public: SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } // This is a cunning lie. DiagnosticBuilder actually performs move // construction in its copy constructor (but due to varied uses, it's not // possible to conveniently express this as actual move construction). So // the default copy ctor here is fine, because the base class disables the // source anyway, so the user-defined ~SemaDiagnosticBuilder is a safe no-op // in that case anwyay. SemaDiagnosticBuilder(const SemaDiagnosticBuilder&) = default; ~SemaDiagnosticBuilder() { // If we aren't active, there is nothing to do. if (!isActive()) return; // Otherwise, we need to emit the diagnostic. First flush the underlying // DiagnosticBuilder data, and clear the diagnostic builder itself so it // won't emit the diagnostic in its own destructor. // // This seems wasteful, in that as written the DiagnosticBuilder dtor will // do its own needless checks to see if the diagnostic needs to be // emitted. However, because we take care to ensure that the builder // objects never escape, a sufficiently smart compiler will be able to // eliminate that code. FlushCounts(); Clear(); // Dispatch to Sema to emit the diagnostic. SemaRef.EmitCurrentDiagnostic(DiagID); } /// Teach operator<< to produce an object of the correct type. template friend const SemaDiagnosticBuilder &operator<<( const SemaDiagnosticBuilder &Diag, const T &Value) { const DiagnosticBuilder &BaseDiag = Diag; BaseDiag << Value; return Diag; } }; /// \brief Emit a diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { DiagnosticBuilder DB = Diags.Report(Loc, DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } /// \brief Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); /// \brief Build a partial diagnostic. PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h bool findMacroSpelling(SourceLocation &loc, StringRef name); /// \brief Get a string to suggest for zero-initialization of a type. std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const; std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const; /// \brief Calls \c Lexer::getLocForEndOfToken() SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); /// \brief Retrieve the module loader associated with the preprocessor. ModuleLoader &getModuleLoader() const; void emitAndClearUnusedLocalTypedefWarnings(); void ActOnEndOfTranslationUnit(); void CheckDelegatingCtorCycles(); Scope *getScopeForContext(DeclContext *Ctx); void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); sema::LambdaScopeInfo *PushLambdaScope(); /// \brief This is used to inform Sema what the current TemplateParameterDepth /// is during Parsing. Currently it is used to pass on the depth /// when parsing generic lambda 'auto' parameters. void RecordParsingTemplateParameterDepth(unsigned Depth); void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K); void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP = nullptr, const Decl *D = nullptr, const BlockExpr *blkExpr = nullptr); sema::FunctionScopeInfo *getCurFunction() const { return FunctionScopes.back(); } sema::FunctionScopeInfo *getEnclosingFunction() const { if (FunctionScopes.empty()) return nullptr; for (int e = FunctionScopes.size()-1; e >= 0; --e) { if (isa(FunctionScopes[e])) continue; return FunctionScopes[e]; } return nullptr; } template void recordUseOfEvaluatedWeak(const ExprT *E, bool IsRead=true) { if (!isUnevaluatedContext()) getCurFunction()->recordUseOfWeak(E, IsRead); } void PushCompoundScope(); void PopCompoundScope(); sema::CompoundScopeInfo &getCurCompoundScope() const; bool hasAnyUnrecoverableErrorsInThisFunction() const; /// \brief Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); /// Retrieve the current lambda scope info, if any. /// \param IgnoreNonLambdaCapturingScope true if should find the top-most /// lambda scope info ignoring all inner capturing scopes that are not /// lambda scopes. sema::LambdaScopeInfo * getCurLambda(bool IgnoreNonLambdaCapturingScope = false); /// \brief Retrieve the current generic lambda info, if any. sema::LambdaScopeInfo *getCurGenericLambda(); /// \brief Retrieve the current captured region, if any. sema::CapturedRegionScopeInfo *getCurCapturedRegion(); /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls SmallVectorImpl &WeakTopLevelDecls() { return WeakTopLevelDecl; } void ActOnComment(SourceRange Comment); //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, const DeclSpec *DS = nullptr); QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA, const DeclSpec *DS = nullptr); QualType BuildPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildReferenceType(QualType T, bool LValueRef, SourceLocation Loc, DeclarationName Entity); QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceRange Brackets, DeclarationName Entity); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); /// \brief Build a function type. /// /// This routine checks the function type according to C++ rules and /// under the assumption that the result type and parameter types have /// just been instantiated from a template. It therefore duplicates /// some of the behavior of GetTypeForDeclarator, but in a much /// simpler form that is only suitable for this narrow use case. /// /// \param T The return type of the function. /// /// \param ParamTypes The parameter types of the function. This array /// will be modified to account for adjustments to the types of the /// function parameters. /// /// \param Loc The location of the entity whose type involves this /// function type or, if there is no such entity, the location of the /// type that will have function type. /// /// \param Entity The name of the entity that involves the function /// type, if known. /// /// \param EPI Extra information about the function type. Usually this will /// be taken from an existing function with the same prototype. /// /// \returns A suitable function type, if there are no errors. The /// unqualified type will always be a FunctionProtoType. /// Otherwise, returns a NULL type. QualType BuildFunctionType(QualType T, MutableArrayRef ParamTypes, SourceLocation Loc, DeclarationName Entity, const FunctionProtoType::ExtProtoInfo &EPI); QualType BuildMemberPointerType(QualType T, QualType Class, SourceLocation Loc, DeclarationName Entity); QualType BuildBlockPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildParenType(QualType T); QualType BuildAtomicType(QualType T, SourceLocation Loc); QualType BuildReadPipeType(QualType T, SourceLocation Loc); QualType BuildWritePipeType(QualType T, SourceLocation Loc); TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo); /// \brief Package the given type and TSI into a ParsedType. ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); DeclarationNameInfo GetNameForDeclarator(Declarator &D); DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = nullptr); CanThrowResult canThrow(const Expr *E); const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT); void UpdateExceptionSpec(FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI); bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range); bool CheckDistantExceptionSpec(QualType T); bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); bool CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool CheckEquivalentExceptionSpec( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, SourceLocation SubLoc); bool CheckParamExceptionSpec(const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, const FunctionProtoType *Target, SourceLocation TargetLoc, const FunctionProtoType *Source, SourceLocation SourceLoc); TypeResult ActOnTypeName(Scope *S, Declarator &D); /// \brief The parser has parsed the context-sensitive type 'instancetype' /// in an Objective-C message declaration. Return the appropriate type. ParsedType ActOnObjCInstanceType(SourceLocation Loc); /// \brief Abstract class used to diagnose incomplete types. struct TypeDiagnoser { TypeDiagnoser() {} virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) = 0; virtual ~TypeDiagnoser() {} }; static int getPrintable(int I) { return I; } static unsigned getPrintable(unsigned I) { return I; } static bool getPrintable(bool B) { return B; } static const char * getPrintable(const char *S) { return S; } static StringRef getPrintable(StringRef S) { return S; } static const std::string &getPrintable(const std::string &S) { return S; } static const IdentifierInfo *getPrintable(const IdentifierInfo *II) { return II; } static DeclarationName getPrintable(DeclarationName N) { return N; } static QualType getPrintable(QualType T) { return T; } static SourceRange getPrintable(SourceRange R) { return R; } static SourceRange getPrintable(SourceLocation L) { return L; } static SourceRange getPrintable(const Expr *E) { return E->getSourceRange(); } static SourceRange getPrintable(TypeLoc TL) { return TL.getSourceRange();} template class BoundTypeDiagnoser : public TypeDiagnoser { unsigned DiagID; std::tuple Args; template void emit(const SemaDiagnosticBuilder &DB, llvm::index_sequence) const { // Apply all tuple elements to the builder in order. bool Dummy[] = {false, (DB << getPrintable(std::get(Args)))...}; (void)Dummy; } public: BoundTypeDiagnoser(unsigned DiagID, const Ts &...Args) : TypeDiagnoser(), DiagID(DiagID), Args(Args...) { assert(DiagID != 0 && "no diagnostic for type diagnoser"); } void diagnose(Sema &S, SourceLocation Loc, QualType T) override { const SemaDiagnosticBuilder &DB = S.Diag(Loc, DiagID); emit(DB, llvm::index_sequence_for()); DB << T; } }; private: bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, TypeDiagnoser *Diagnoser); struct ModuleScope { clang::Module *Module; VisibleModuleSet OuterVisibleModules; }; /// The modules we're currently parsing. llvm::SmallVector ModuleScopes; /// Get the module whose scope we are currently within. Module *getCurrentModule() const { return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; } VisibleModuleSet VisibleModules; - Module *CachedFakeTopLevelModule; - public: /// \brief Get the module owning an entity. - Module *getOwningModule(Decl *Entity); + Module *getOwningModule(Decl *Entity) { return Entity->getOwningModule(); } /// \brief Make a merged definition of an existing hidden definition \p ND /// visible at the specified location. void makeMergedDefinitionVisible(NamedDecl *ND); bool isModuleVisible(Module *M) { return VisibleModules.isVisible(M); } /// Determine whether a declaration is visible to name lookup. bool isVisible(const NamedDecl *D) { return !D->isHidden() || isVisibleSlow(D); } /// Determine whether any declaration of an entity is visible. bool hasVisibleDeclaration(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr) { return isVisible(D) || hasVisibleDeclarationSlow(D, Modules); } bool hasVisibleDeclarationSlow(const NamedDecl *D, llvm::SmallVectorImpl *Modules); bool hasVisibleMergedDefinition(NamedDecl *Def); /// Determine if \p D has a visible definition. If not, suggest a declaration /// that should be made visible to expose the definition. bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, bool OnlyNeedComplete = false); bool hasVisibleDefinition(const NamedDecl *D) { NamedDecl *Hidden; return hasVisibleDefinition(const_cast(D), &Hidden); } /// Determine if the template parameter \p D has a visible default argument. bool hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if there is a visible declaration of \p D that is a member /// specialization declaration (as opposed to an instantiated declaration). bool hasVisibleMemberSpecialization( const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if \p A and \p B are equivalent internal linkage declarations /// from different modules, and thus an ambiguity error can be downgraded to /// an extension warning. bool isEquivalentInternalLinkageDeclaration(const NamedDecl *A, const NamedDecl *B); void diagnoseEquivalentInternalLinkageDeclarations( SourceLocation Loc, const NamedDecl *D, ArrayRef Equiv); bool isCompleteType(SourceLocation Loc, QualType T) { return !RequireCompleteTypeImpl(Loc, T, nullptr); } bool RequireCompleteType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID); template bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteType(Loc, T, Diagnoser); } void completeExprArrayBound(Expr *E); bool RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser); bool RequireCompleteExprType(Expr *E, unsigned DiagID); template bool RequireCompleteExprType(Expr *E, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteExprType(E, Diagnoser); } bool RequireLiteralType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID); template bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireLiteralType(Loc, T, Diagnoser); } QualType getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). QualType BuildDecltypeType(Expr *E, SourceLocation Loc, bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // struct SkipBodyInfo { SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {} bool ShouldSkip; NamedDecl *Previous; }; DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr); void DiagnoseUseOfUnimplementedSelectors(); bool isSimpleTypeSpecifier(tok::TokenKind Kind) const; ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS = nullptr, bool isClassName = false, bool HasTrailingDot = false, ParsedType ObjectType = nullptr, bool IsCtorOrDtorName = false, bool WantNontrivialTypeSourceInfo = false, bool IsClassTemplateDeductionContext = true, IdentifierInfo **CorrectedII = nullptr); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); void DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, bool IsTemplateName = false); /// Attempt to behave like MSVC in situations where lookup of an unqualified /// type name has failed in a dependent context. In these situations, we /// automatically form a DependentTypeName that will retry lookup in a related /// scope during instantiation. ParsedType ActOnMSVCUnknownTypeName(const IdentifierInfo &II, SourceLocation NameLoc, bool IsTemplateTypeArg); /// \brief Describes the result of the name lookup and resolution performed /// by \c ClassifyName(). enum NameClassificationKind { NC_Unknown, NC_Error, NC_Keyword, NC_Type, NC_Expression, NC_NestedNameSpecifier, NC_TypeTemplate, NC_VarTemplate, NC_FunctionTemplate }; class NameClassification { NameClassificationKind Kind; ExprResult Expr; TemplateName Template; ParsedType Type; const IdentifierInfo *Keyword; explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} public: NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {} NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword), Keyword(Keyword) { } static NameClassification Error() { return NameClassification(NC_Error); } static NameClassification Unknown() { return NameClassification(NC_Unknown); } static NameClassification NestedNameSpecifier() { return NameClassification(NC_NestedNameSpecifier); } static NameClassification TypeTemplate(TemplateName Name) { NameClassification Result(NC_TypeTemplate); Result.Template = Name; return Result; } static NameClassification VarTemplate(TemplateName Name) { NameClassification Result(NC_VarTemplate); Result.Template = Name; return Result; } static NameClassification FunctionTemplate(TemplateName Name) { NameClassification Result(NC_FunctionTemplate); Result.Template = Name; return Result; } NameClassificationKind getKind() const { return Kind; } ParsedType getType() const { assert(Kind == NC_Type); return Type; } ExprResult getExpression() const { assert(Kind == NC_Expression); return Expr; } TemplateName getTemplateName() const { assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate || Kind == NC_VarTemplate); return Template; } TemplateNameKind getTemplateNameKind() const { switch (Kind) { case NC_TypeTemplate: return TNK_Type_template; case NC_FunctionTemplate: return TNK_Function_template; case NC_VarTemplate: return TNK_Var_template; default: llvm_unreachable("unsupported name classification."); } } }; /// \brief Perform name lookup on the given name, classifying it based on /// the results of name lookup and the following token. /// /// This routine is used by the parser to resolve identifiers and help direct /// parsing. When the identifier cannot be found, this routine will attempt /// to correct the typo and classify based on the resulting name. /// /// \param S The scope in which we're performing name lookup. /// /// \param SS The nested-name-specifier that precedes the name. /// /// \param Name The identifier. If typo correction finds an alternative name, /// this pointer parameter will be updated accordingly. /// /// \param NameLoc The location of the identifier. /// /// \param NextToken The token following the identifier. Used to help /// disambiguate the name. /// /// \param IsAddressOfOperand True if this name is the operand of a unary /// address of ('&') expression, assuming it is classified as an /// expression. /// /// \param CCC The correction callback, if typo correction is desired. NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken, bool IsAddressOfOperand, std::unique_ptr CCC = nullptr); /// Describes the detailed kind of a template name. Used in diagnostics. enum class TemplateNameKindForDiagnostics { ClassTemplate, FunctionTemplate, VarTemplate, AliasTemplate, TemplateTemplateParam, DependentTemplate }; TemplateNameKindForDiagnostics getTemplateNameKindForDiagnostics(TemplateName Name); /// Determine whether it's plausible that E was intended to be a /// template-name. bool mightBeIntendedToBeTemplateName(ExprResult E) { if (!getLangOpts().CPlusPlus || E.isInvalid()) return false; if (auto *DRE = dyn_cast(E.get())) return !DRE->hasExplicitTemplateArgs(); if (auto *ME = dyn_cast(E.get())) return !ME->hasExplicitTemplateArgs(); // Any additional cases recognized here should also be handled by // diagnoseExprIntendedAsTemplateName. return false; } void diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, SourceLocation Less, SourceLocation Greater); Decl *ActOnDeclarator(Scope *S, Declarator &D); NamedDecl *HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists); void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, SourceLocation Loc); void diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, SourceLocation FallbackLoc, SourceLocation ConstQualLoc = SourceLocation(), SourceLocation VolatileQualLoc = SourceLocation(), SourceLocation RestrictQualLoc = SourceLocation(), SourceLocation AtomicQualLoc = SourceLocation(), SourceLocation UnalignedQualLoc = SourceLocation()); static bool adjustContextForLocalExternDecl(DeclContext *&DC); void DiagnoseFunctionSpecifiers(const DeclSpec &DS); NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D, const LookupResult &R); NamedDecl *getShadowedDeclaration(const VarDecl *D, const LookupResult &R); void CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R); void CheckShadow(Scope *S, VarDecl *D); /// Warn if 'E', which is an expression that is about to be modified, refers /// to a shadowing declaration. void CheckShadowingDeclModification(Expr *E, SourceLocation Loc); void DiagnoseShadowingLambdaDecls(const sema::LambdaScopeInfo *LSI); private: /// Map of current shadowing declarations to shadowed declarations. Warn if /// it looks like the user is trying to modify the shadowing declaration. llvm::DenseMap ShadowingDecls; public: void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); void handleTagNumbering(const TagDecl *Tag, Scope *TagScope); void setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, TypedefNameDecl *NewTD); void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous); NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D, LookupResult &Previous, bool &Redeclaration); NamedDecl *ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope, ArrayRef Bindings = None); NamedDecl * ActOnDecompositionDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists); // Returns true if the variable declaration is a redeclaration bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); void CheckVariableDeclarationType(VarDecl *NewVD); bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, Expr *Init); void CheckCompleteVariableDeclaration(VarDecl *VD); void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD); void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope); bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); bool CheckConstexprFunctionDecl(const FunctionDecl *FD); bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body); void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD); void FindHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl &OverloadedMethods); void NoteHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl &OverloadedMethods); // Returns true if the function declaration is a redeclaration bool CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsMemberSpecialization); bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); Decl *ActOnParamDeclarator(Scope *S, Declarator &D); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T); ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, StorageClass SC); void ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, Expr *defarg); void ActOnParamUnparsedDefaultArgument(Decl *param, SourceLocation EqualLoc, SourceLocation ArgLoc); void ActOnParamDefaultArgumentError(Decl *param, SourceLocation EqualLoc); bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, SourceLocation EqualLoc); void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit); void ActOnUninitializedDecl(Decl *dcl); void ActOnInitializerError(Decl *Dcl); void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); void ActOnCXXForRangeDecl(Decl *D); StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, ParsedAttributes &Attrs, SourceLocation AttrEnd); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); void FinalizeDeclaration(Decl *D); DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, ArrayRef Group); DeclGroupPtrTy BuildDeclaratorGroup(MutableArrayRef Group); /// Should be called on all declarations that might have attached /// documentation comments. void ActOnDocumentableDecl(Decl *D); void ActOnDocumentableDecls(ArrayRef Group); void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls); void CheckForFunctionRedefinition( FunctionDecl *FD, const FunctionDecl *EffectiveDefinition = nullptr, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, SkipBodyInfo *SkipBody = nullptr); void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); bool isObjCMethodDecl(Decl *D) { return D && isa(D); } /// \brief Determine whether we can delay parsing the body of a function or /// function template until it is used, assuming we don't care about emitting /// code for that function. /// /// This will be \c false if we may need the body of the function in the /// middle of parsing an expression (where it's impractical to switch to /// parsing a different function), for instance, if it's constexpr in C++11 /// or has an 'auto' return type in C++14. These cases are essentially bugs. bool canDelayFunctionBody(const Declarator &D); /// \brief Determine whether we can skip parsing the body of a function /// definition, assuming we don't care about analyzing its body or emitting /// code for that function. /// /// This will be \c false only if we may need the body of the function in /// order to parse the rest of the program (for instance, if it is /// \c constexpr in C++11 or has an 'auto' return type in C++14). bool canSkipFunctionBody(Decl *D); void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); Decl *ActOnSkippedFunctionBody(Decl *Decl); void ActOnFinishInlineFunctionDef(FunctionDecl *D); /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an /// attribute for which parsing is delayed. void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs); /// \brief Diagnose any unused parameters in the given sequence of /// ParmVarDecl pointers. void DiagnoseUnusedParameters(ArrayRef Parameters); /// \brief Diagnose whether the size of parameters or return value of a /// function or obj-c method definition is pass-by-value and larger than a /// specified threshold. void DiagnoseSizeOfParametersAndReturnValue(ArrayRef Parameters, QualType ReturnTy, NamedDecl *D); void DiagnoseInvalidJumps(Stmt *Body); Decl *ActOnFileScopeAsmDecl(Expr *expr, SourceLocation AsmLoc, SourceLocation RParenLoc); /// \brief Handle a C++11 empty-declaration and attribute-declaration. Decl *ActOnEmptyDeclaration(Scope *S, AttributeList *AttrList, SourceLocation SemiLoc); enum class ModuleDeclKind { Module, ///< 'module X;' Partition, ///< 'module partition X;' Implementation, ///< 'module implementation X;' }; /// The parser has processed a module-declaration that begins the definition /// of a module interface or implementation. DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path); /// \brief The parser has processed a module import declaration. /// /// \param AtLoc The location of the '@' symbol, if any. /// /// \param ImportLoc The location of the 'import' keyword. /// /// \param Path The module access path. DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc, ModuleIdPath Path); /// \brief The parser has processed a module import translated from a /// #include or similar preprocessing directive. void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod); void BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod); /// \brief The parsed has entered a submodule. void ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod); /// \brief The parser has left a submodule. void ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod); /// \brief Create an implicit import of the given module at the given /// source location, for error recovery, if possible. /// /// This routine is typically used when an entity found by name lookup /// is actually hidden within a module that we know about but the user /// has forgotten to import. void createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod); /// Kinds of missing import. Note, the values of these enumerators correspond /// to %select values in diagnostics. enum class MissingImportKind { Declaration, Definition, DefaultArgument, ExplicitSpecialization, PartialSpecialization }; /// \brief Diagnose that the specified declaration needs to be visible but /// isn't, and suggest a module import that would resolve the problem. void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, MissingImportKind MIK, bool Recover = true); void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, SourceLocation DeclLoc, ArrayRef Modules, MissingImportKind MIK, bool Recover); Decl *ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, SourceLocation LBraceLoc); Decl *ActOnFinishExportDecl(Scope *S, Decl *ExportDecl, SourceLocation RBraceLoc); /// \brief We've found a use of a templated declaration that would trigger an /// implicit instantiation. Check that any relevant explicit specializations /// and partial specializations are visible, and diagnose if not. void checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); /// \brief We've found a use of a template specialization that would select a /// partial specialization. Check that the partial specialization is visible, /// and diagnose if not. void checkPartialSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); /// \brief Retrieve a suitable printing policy. PrintingPolicy getPrintingPolicy() const { return getPrintingPolicy(Context, PP); } /// \brief Retrieve a suitable printing policy. static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, const Preprocessor &PP); /// Scope actions. void ActOnPopScope(SourceLocation Loc, Scope *S); void ActOnTranslationUnitScope(Scope *S); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, RecordDecl *&AnonRecord); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation, RecordDecl *&AnonRecord); Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, AccessSpecifier AS, RecordDecl *Record, const PrintingPolicy &Policy); Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record); /// Common ways to introduce type names without a tag for use in diagnostics. /// Keep in sync with err_tag_reference_non_tag. enum NonTagKind { NTK_NonStruct, NTK_NonClass, NTK_NonUnion, NTK_NonEnum, NTK_Typedef, NTK_TypeAlias, NTK_Template, NTK_TypeAliasTemplate, NTK_TemplateTemplateArgument, }; /// Given a non-tag type declaration, returns an enum useful for indicating /// what kind of non-tag type this is. NonTagKind getNonTagTypeDeclKind(const Decl *D, TagTypeKind TTK); bool isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo *Name); enum TagUseKind { TUK_Reference, // Reference to a tag: 'struct foo *X;' TUK_Declaration, // Fwd decl of a tag: 'struct foo;' TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' TUK_Friend // Friend declaration: 'friend struct foo;' }; Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, MultiTemplateParamsArg TempParamLists); TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation TagLoc, SourceLocation NameLoc); void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, SmallVectorImpl &Decls); Decl *ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth); FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS); MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS, AttributeList *MSPropertyAttr); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitfieldWidth, InClassInitStyle InitStyle, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D = nullptr); bool CheckNontrivialField(FieldDecl *FD); void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, bool Diagnose = false); CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); void ActOnLastBitfield(SourceLocation DeclStart, SmallVectorImpl &AllIvarDecls); Decl *ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, tok::ObjCKeywordKind visibility); // This is used for both record definitions and ObjC interface declarations. void ActOnFields(Scope* S, SourceLocation RecLoc, Decl *TagDecl, ArrayRef Fields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList); /// ActOnTagStartDefinition - Invoked when we have entered the /// scope of a tag's definition (e.g., for an enumeration, class, /// struct, or union). void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); typedef void *SkippedDefinitionContext; /// \brief Invoked when we enter a tag definition that we're skipping. SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD); Decl *ActOnObjCContainerStartDefinition(Decl *IDecl); /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a /// C++ record definition's base-specifiers clause and are starting its /// member declarations. void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, SourceLocation FinalLoc, bool IsFinalSpelledSealed, SourceLocation LBraceLoc); /// ActOnTagFinishDefinition - Invoked once we have finished parsing /// the definition of a tag (enumeration, class, struct, or union). void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl, SourceRange BraceRange); void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context); void ActOnObjCContainerFinishDefinition(); /// \brief Invoked when we must temporarily exit the objective-c container /// scope for parsing/looking-up C constructs. /// /// Must be followed by a call to \see ActOnObjCReenterContainerContext void ActOnObjCTemporaryExitContainerContext(DeclContext *DC); void ActOnObjCReenterContainerContext(DeclContext *DC); /// ActOnTagDefinitionError - Invoked when there was an unrecoverable /// error parsing the definition of a tag. void ActOnTagDefinitionError(Scope *S, Decl *TagDecl); EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, Expr *val); bool CheckEnumUnderlyingType(TypeSourceInfo *TI); bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, QualType EnumUnderlyingTy, bool EnumUnderlyingIsImplicit, const EnumDecl *Prev); /// Determine whether the body of an anonymous enumeration should be skipped. /// \param II The name of the first enumerator. SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, SourceLocation IILoc); Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, AttributeList *Attrs, SourceLocation EqualLoc, Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, Decl *EnumDecl, ArrayRef Elements, Scope *S, AttributeList *Attr); DeclContext *getContainingDC(DeclContext *DC); /// Set the current declaration context until it gets popped. void PushDeclContext(Scope *S, DeclContext *DC); void PopDeclContext(); /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. void EnterDeclaratorContext(Scope *S, DeclContext *DC); void ExitDeclaratorContext(Scope *S); /// Push the parameters of D, which must be a function, into scope. void ActOnReenterFunctionContext(Scope* S, Decl* D); void ActOnExitFunctionContext(); DeclContext *getFunctionLevelDeclContext(); /// getCurFunctionDecl - If inside of a function body, this returns a pointer /// to the function decl for the function being parsed. If we're currently /// in a 'block', this returns the containing context. FunctionDecl *getCurFunctionDecl(); /// getCurMethodDecl - If inside of a method body, this returns a pointer to /// the method decl for the method being parsed. If we're currently /// in a 'block', this returns the containing context. ObjCMethodDecl *getCurMethodDecl(); /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method /// or C function we're in, otherwise return null. If we're currently /// in a 'block', this returns the containing context. NamedDecl *getCurFunctionOrMethodDecl(); /// Add this decl to the scope shadowed decl chains. void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); /// \brief Make the given externally-produced declaration visible at the /// top level scope. /// /// \param D The externally-produced declaration to push. /// /// \param Name The name of the externally-produced declaration. void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. /// /// \param AllowInlineNamespace If \c true, allow the declaration to be in the /// enclosing namespace set of the context, rather than contained /// directly within it. bool isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S = nullptr, bool AllowInlineNamespace = false); /// Finds the scope corresponding to the given decl context, if it /// happens to be an enclosing scope. Otherwise return NULL. static Scope *getScopeForDeclContext(Scope *S, DeclContext *DC); /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo); bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); /// \brief Describes the kind of merge to perform for availability /// attributes (including "deprecated", "unavailable", and "availability"). enum AvailabilityMergeKind { /// \brief Don't merge availability attributes at all. AMK_None, /// \brief Merge availability attributes for a redeclaration, which requires /// an exact match. AMK_Redeclaration, /// \brief Merge availability attributes for an override, which requires /// an exact match or a weakening of constraints. AMK_Override, /// \brief Merge availability attributes for an implementation of /// a protocol requirement. AMK_ProtocolImplementation, }; /// Attribute merging methods. Return true if a new attribute was added. AvailabilityAttr *mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK, unsigned AttrSpellingListIndex); TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range, TypeVisibilityAttr::VisibilityType Vis, unsigned AttrSpellingListIndex); VisibilityAttr *mergeVisibilityAttr(Decl *D, SourceRange Range, VisibilityAttr::VisibilityType Vis, unsigned AttrSpellingListIndex); UuidAttr *mergeUuidAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex, StringRef Uuid); DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); MSInheritanceAttr * mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, unsigned AttrSpellingListIndex, MSInheritanceAttr::Spelling SemanticSpelling); FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range, IdentifierInfo *Format, int FormatIdx, int FirstArg, unsigned AttrSpellingListIndex); SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex); AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, NamedDecl *&Old, Scope *S, bool MergeTypeWithOld); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, Scope *S, bool MergeTypeWithOld); void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old); void MergeVarDecl(VarDecl *New, LookupResult &Previous); void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld); void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn); void notePreviousDefinition(SourceLocation Old, SourceLocation New); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); // AssignmentAction - This is used by all the assignment diagnostic functions // to represent what is actually causing the operation enum AssignmentAction { AA_Assigning, AA_Passing, AA_Returning, AA_Converting, AA_Initializing, AA_Sending, AA_Casting, AA_Passing_CFAudited }; /// C++ Overloading. enum OverloadKind { /// This is a legitimate overload: the existing declarations are /// functions or function templates with different signatures. Ovl_Overload, /// This is not an overload because the signature exactly matches /// an existing declaration. Ovl_Match, /// This is not an overload because the lookup results contain a /// non-function. Ovl_NonFunction }; OverloadKind CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &OldDecls, NamedDecl *&OldDecl, bool IsForUsingDecl); bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, bool ConsiderCudaAttrs = true); /// \brief Checks availability of the function depending on the current /// function context.Inside an unavailable function,unavailability is ignored. /// /// \returns true if \p FD is unavailable and current context is inside /// an available function, false otherwise. bool isFunctionConsideredUnavailable(FunctionDecl *FD); ImplicitConversionSequence TryImplicitConversion(Expr *From, QualType ToType, bool SuppressUserConversions, bool AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); bool IsComplexPromotion(QualType FromType, QualType ToType); bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCWritebackConversion(QualType FromType, QualType ToType, QualType &ConvertedType); bool IsBlockPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType); bool FunctionParamTypesAreEqual(const FunctionProtoType *OldType, const FunctionProtoType *NewType, unsigned *ArgPos = nullptr); void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, QualType FromType, QualType ToType); void maybeExtendBlockObject(ExprResult &E); CastKind PrepareCastToObjCObjectPointer(ExprResult &E); bool CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath& BasePath, bool IgnoreBaseAccess, bool Diagnose = true); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType &ConvertedType); bool CheckMemberPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath &BasePath, bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType, bool CStyle, bool &ObjCLifetimeConversion); bool IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, const VarDecl *NRVOCandidate, QualType ResultType, Expr *Value, bool AllowNRVO = true); bool CanPerformCopyInitialization(const InitializedEntity &Entity, ExprResult Init); ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init, bool TopLevelOfInitList = false, bool AllowExplicit = false); ExprResult PerformObjectArgumentInitialization(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method); ExprResult PerformContextuallyConvertToBool(Expr *From); ExprResult PerformContextuallyConvertToObjCPointer(Expr *From); /// Contexts in which a converted constant expression is required. enum CCEKind { CCEK_CaseValue, ///< Expression in a case label. CCEK_Enumerator, ///< Enumerator value with fixed underlying type. CCEK_TemplateArg, ///< Value of a non-type template parameter. CCEK_NewExpr, ///< Constant expression in a noptr-new-declarator. CCEK_ConstexprIf ///< Condition in a constexpr if statement. }; ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, llvm::APSInt &Value, CCEKind CCE); ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, APValue &Value, CCEKind CCE); /// \brief Abstract base class used to perform a contextual implicit /// conversion from an expression to any type passing a filter. class ContextualImplicitConverter { public: bool Suppress; bool SuppressConversion; ContextualImplicitConverter(bool Suppress = false, bool SuppressConversion = false) : Suppress(Suppress), SuppressConversion(SuppressConversion) {} /// \brief Determine whether the specified type is a valid destination type /// for this conversion. virtual bool match(QualType T) = 0; /// \brief Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a diagnostic when the expression has incomplete class type. virtual SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a diagnostic when the only matching conversion function /// is explicit. virtual SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; /// \brief Emits a note for the explicit conversion function. virtual SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// \brief Emits a diagnostic when there are multiple possible conversion /// functions. virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a note for one of the candidate conversions. virtual SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// \brief Emits a diagnostic when we picked a conversion function /// (for cases when we are not allowed to pick a conversion function). virtual SemaDiagnosticBuilder diagnoseConversion( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; virtual ~ContextualImplicitConverter() {} }; class ICEConvertDiagnoser : public ContextualImplicitConverter { bool AllowScopedEnumerations; public: ICEConvertDiagnoser(bool AllowScopedEnumerations, bool Suppress, bool SuppressConversion) : ContextualImplicitConverter(Suppress, SuppressConversion), AllowScopedEnumerations(AllowScopedEnumerations) {} /// Match an integral or (possibly scoped) enumeration type. bool match(QualType T) override; SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { return diagnoseNotInt(S, Loc, T); } /// \brief Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0; }; /// Perform a contextual implicit conversion. ExprResult PerformContextualImplicitConversion( SourceLocation Loc, Expr *FromE, ContextualImplicitConverter &Converter); enum ObjCSubscriptKind { OS_Array, OS_Dictionary, OS_Error }; ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE); // Note that LK_String is intentionally after the other literals, as // this is used for diagnostics logic. enum ObjCLiteralKind { LK_Array, LK_Dictionary, LK_Numeric, LK_Boxed, LK_String, LK_Block, LK_None }; ObjCLiteralKind CheckLiteralKind(Expr *FromE); ExprResult PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member); // Members have to be NamespaceDecl* or TranslationUnitDecl*. // TODO: make this is a typesafe union. typedef llvm::SmallSetVector AssociatedNamespaceSet; typedef llvm::SmallSetVector AssociatedClassSet; void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = false, ConversionSequenceList EarlyConversions = None); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, ArrayRef Args, OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, bool SuppressUserConversions = false, bool PartialOverloading = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, ConversionSequenceList EarlyConversions = None); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false); bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate, ArrayRef ParamTypes, ArrayRef Args, OverloadCandidateSet &CandidateSet, ConversionSequenceList &Conversions, bool SuppressUserConversions, CXXRecordDecl *ActingContext = nullptr, QualType ObjectType = QualType(), Expr::Classification ObjectClassification = {}); void AddConversionCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet, bool AllowObjCConversionOnExplicit); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, Expr *Object, ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef Args, OverloadCandidateSet& CandidateSet, SourceRange OpRange = SourceRange()); void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, SourceLocation Loc, ArrayRef Args, TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, QualType DestType = QualType(), bool TakingAddress = false); // Emit as a series of 'note's all template and non-templates identified by // the expression Expr void NoteAllOverloadCandidates(Expr *E, QualType DestType = QualType(), bool TakingAddress = false); /// Check the enable_if expressions on the given function. Returns the first /// failing attribute, or NULL if they were all successful. EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef Args, bool MissingImplicitThis = false); /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any /// non-ArgDependent DiagnoseIfAttrs. /// /// Argument-dependent diagnose_if attributes should be checked each time a /// function is used as a direct callee of a function call. /// /// Returns true if any errors were emitted. bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function, const Expr *ThisArg, ArrayRef Args, SourceLocation Loc); /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any /// ArgDependent DiagnoseIfAttrs. /// /// Argument-independent diagnose_if attributes should be checked on every use /// of a function. /// /// Returns true if any errors were emitted. bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function, SourceLocation Loc); /// Returns whether the given function's address can be taken or not, /// optionally emitting a diagnostic if the address can't be taken. /// /// Returns false if taking the address of the function is illegal. bool checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, bool Complain = false, SourceLocation Loc = SourceLocation()); // [PossiblyAFunctionType] --> [Return] // NonFunctionType --> NonFunctionType // R (A) --> R(A) // R (*)(A) --> R (A) // R (&)(A) --> R (A) // R (S::*)(A) --> R (A) QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); FunctionDecl * ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType, bool Complain, DeclAccessPair &Found, bool *pHadMultipleCandidates = nullptr); FunctionDecl * resolveAddressOfOnlyViableOverloadCandidate(Expr *E, DeclAccessPair &FoundResult); bool resolveAndFixAddressOfOnlyViableOverloadCandidate( ExprResult &SrcExpr, bool DoFunctionPointerConversion = false); FunctionDecl * ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, bool Complain = false, DeclAccessPair *Found = nullptr); bool ResolveAndFixSingleFunctionTemplateSpecialization( ExprResult &SrcExpr, bool DoFunctionPointerConverion = false, bool Complain = false, SourceRange OpRangeForComplaining = SourceRange(), QualType DestTypeForComplaining = QualType(), unsigned DiagIDForComplaining = 0); Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, FunctionDecl *Fn); ExprResult FixOverloadedFunctionReference(ExprResult, DeclAccessPair FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); // An enum used to represent the different possible results of building a // range-based for loop. enum ForRangeStatus { FRS_Success, FRS_NoViableFunction, FRS_DiagnosticIssued }; ForRangeStatus BuildForRangeBeginEndCall(SourceLocation Loc, SourceLocation RangeLoc, const DeclarationNameInfo &NameInfo, LookupResult &MemberLookup, OverloadCandidateSet *CandidateSet, Expr *Range, ExprResult *CallExpr); ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig, bool AllowTypoCorrection=true, bool CalleesAddressIsTaken=false); bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, MultiExprArg Args, SourceLocation RParenLoc, OverloadCandidateSet *CandidateSet, ExprResult *Result); ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *input); ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS); ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, Expr *Base,Expr *Idx); ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc); ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool *NoArrowOperatorFound = nullptr); /// CheckCallReturnType - Checks that a call expression's return type is /// complete. Returns true on failure. The location passed in is the location /// that best represents the call. bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. bool CheckParmsForFunctionDef(ArrayRef Parameters, bool CheckParameterNames); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); Scope *getNonFieldDeclScope(Scope *S); /// \name Name lookup /// /// These routines provide name lookup that is used during semantic /// analysis to resolve the various kinds of names (identifiers, /// overloaded operator names, constructor names, etc.) into zero or /// more declarations within a particular scope. The major entry /// points are LookupName, which performs unqualified name lookup, /// and LookupQualifiedName, which performs qualified name lookup. /// /// All name lookup is performed based on some specific criteria, /// which specify what names will be visible to name lookup and how /// far name lookup should work. These criteria are important both /// for capturing language semantics (certain lookups will ignore /// certain names, for example) and for performance, since name /// lookup is often a bottleneck in the compilation of C++. Name /// lookup criteria is specified via the LookupCriteria enumeration. /// /// The results of name lookup can vary based on the kind of name /// lookup performed, the current language, and the translation /// unit. In C, for example, name lookup will either return nothing /// (no entity found) or a single declaration. In C++, name lookup /// can additionally refer to a set of overloaded functions or /// result in an ambiguity. All of the possible results of name /// lookup are captured by the LookupResult class, which provides /// the ability to distinguish among them. //@{ /// @brief Describes the kind of name lookup to perform. enum LookupNameKind { /// Ordinary name lookup, which finds ordinary names (functions, /// variables, typedefs, etc.) in C and most kinds of names /// (functions, variables, members, types, etc.) in C++. LookupOrdinaryName = 0, /// Tag name lookup, which finds the names of enums, classes, /// structs, and unions. LookupTagName, /// Label name lookup. LookupLabel, /// Member name lookup, which finds the names of /// class/struct/union members. LookupMemberName, /// Look up of an operator name (e.g., operator+) for use with /// operator overloading. This lookup is similar to ordinary name /// lookup, but will ignore any declarations that are class members. LookupOperatorName, /// Look up of a name that precedes the '::' scope resolution /// operator in C++. This lookup completely ignores operator, object, /// function, and enumerator names (C++ [basic.lookup.qual]p1). LookupNestedNameSpecifierName, /// Look up a namespace name within a C++ using directive or /// namespace alias definition, ignoring non-namespace names (C++ /// [basic.lookup.udir]p1). LookupNamespaceName, /// Look up all declarations in a scope with the given name, /// including resolved using declarations. This is appropriate /// for checking redeclarations for a using declaration. LookupUsingDeclName, /// Look up an ordinary name that is going to be redeclared as a /// name with linkage. This lookup ignores any declarations that /// are outside of the current scope unless they have linkage. See /// C99 6.2.2p4-5 and C++ [basic.link]p6. LookupRedeclarationWithLinkage, /// Look up a friend of a local class. This lookup does not look /// outside the innermost non-class scope. See C++11 [class.friend]p11. LookupLocalFriendName, /// Look up the name of an Objective-C protocol. LookupObjCProtocolName, /// Look up implicit 'self' parameter of an objective-c method. LookupObjCImplicitSelfParam, /// \brief Look up the name of an OpenMP user-defined reduction operation. LookupOMPReductionName, /// \brief Look up any declaration with any name. LookupAnyName }; /// \brief Specifies whether (or how) name lookup is being performed for a /// redeclaration (vs. a reference). enum RedeclarationKind { /// \brief The lookup is a reference to this name that is not for the /// purpose of redeclaring the name. NotForRedeclaration = 0, /// \brief The lookup results will be used for redeclaration of a name, /// if an entity by that name already exists. ForRedeclaration }; /// \brief The possible outcomes of name lookup for a literal operator. enum LiteralOperatorLookupResult { /// \brief The lookup resulted in an error. LOLR_Error, /// \brief The lookup found a single 'cooked' literal operator, which /// expects a normal literal to be built and passed to it. LOLR_Cooked, /// \brief The lookup found a single 'raw' literal operator, which expects /// a string literal containing the spelling of the literal token. LOLR_Raw, /// \brief The lookup found an overload set of literal operator templates, /// which expect the characters of the spelling of the literal token to be /// passed as a non-type template argument pack. LOLR_Template, /// \brief The lookup found an overload set of literal operator templates, /// which expect the character type and characters of the spelling of the /// string literal token to be passed as template arguments. LOLR_StringTemplate }; SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis); typedef std::function TypoDiagnosticGenerator; typedef std::function TypoRecoveryCallback; private: bool CppLookupName(LookupResult &R, Scope *S); struct TypoExprState { std::unique_ptr Consumer; TypoDiagnosticGenerator DiagHandler; TypoRecoveryCallback RecoveryHandler; TypoExprState(); TypoExprState(TypoExprState &&other) noexcept; TypoExprState &operator=(TypoExprState &&other) noexcept; }; /// \brief The set of unhandled TypoExprs and their associated state. llvm::MapVector DelayedTypos; /// \brief Creates a new TypoExpr AST node. TypoExpr *createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC); // \brief The set of known/encountered (unique, canonicalized) NamespaceDecls. // // The boolean value will be true to indicate that the namespace was loaded // from an AST/PCH file, or false otherwise. llvm::MapVector KnownNamespaces; /// \brief Whether we have already loaded known namespaces from an extenal /// source. bool LoadedExternalKnownNamespaces; /// \brief Helper for CorrectTypo and CorrectTypoDelayed used to create and /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction /// should be skipped entirely. std::unique_ptr makeTypoCorrectionConsumer(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery); public: const TypoExprState &getTypoExprState(TypoExpr *TE) const; /// \brief Clears the state of the given TypoExpr. void clearDelayedTypo(TypoExpr *TE); /// \brief Look up a name, looking for a single declaration. Return /// null if the results were absent, ambiguous, or overloaded. /// /// It is preferable to use the elaborated form and explicitly handle /// ambiguity and overloaded. NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl = NotForRedeclaration); bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS); bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl = NotForRedeclaration); bool LookupInSuper(LookupResult &R, CXXRecordDecl *Class); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions); LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc, SourceLocation GnuLabelLoc = SourceLocation()); DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class); CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class, unsigned Quals); CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class, unsigned Quals); CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id); LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef ArgTys, bool AllowRaw, bool AllowTemplate, bool AllowStringTemplate); bool isKnownName(StringRef name); void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, ArrayRef Args, ADLResult &Functions); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true, bool IncludeDependentBases = false); enum CorrectTypoKind { CTK_NonError, // CorrectTypo used in a non error recovery situation. CTK_ErrorRecovery // CorrectTypo used in normal error recovery. }; TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr, bool RecordFailure = true); TypoExpr *CorrectTypoDelayed(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr); /// \brief Process any TypoExprs in the given Expr and its children, /// generating diagnostics as appropriate and returning a new Expr if there /// were typos that were all successfully corrected and ExprError if one or /// more typos could not be corrected. /// /// \param E The Expr to check for TypoExprs. /// /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its /// initializer. /// /// \param Filter A function applied to a newly rebuilt Expr to determine if /// it is an acceptable/usable result from a single combination of typo /// corrections. As long as the filter returns ExprError, different /// combinations of corrections will be tried until all are exhausted. ExprResult CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl = nullptr, llvm::function_ref Filter = [](Expr *E) -> ExprResult { return E; }); ExprResult CorrectDelayedTyposInExpr(Expr *E, llvm::function_ref Filter) { return CorrectDelayedTyposInExpr(E, nullptr, Filter); } ExprResult CorrectDelayedTyposInExpr(ExprResult ER, VarDecl *InitDecl = nullptr, llvm::function_ref Filter = [](Expr *E) -> ExprResult { return E; }) { return ER.isInvalid() ? ER : CorrectDelayedTyposInExpr(ER.get(), Filter); } ExprResult CorrectDelayedTyposInExpr(ExprResult ER, llvm::function_ref Filter) { return CorrectDelayedTyposInExpr(ER, nullptr, Filter); } void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, bool ErrorRecovery = true); void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, const PartialDiagnostic &PrevNote, bool ErrorRecovery = true); void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F); void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses); void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace); void DiagnoseAmbiguousLookup(LookupResult &Result); //@} ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, bool TypoCorrection = false); NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S); void AddKnownFunctionAttributes(FunctionDecl *FD); // More parsing and symbol table subroutines. void ProcessPragmaWeak(Scope *S, Decl *D); // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); // Helper for delayed proccessing of attributes. void ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList); void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, bool IncludeCXX11Attributes = true); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, const AttributeList *AttrList); void checkUnusedDeclAttributes(Declarator &D); /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference /// type as valid. bool isValidPointerAttrType(QualType T, bool RefOkay = false); bool CheckRegparmAttr(const AttributeList &attr, unsigned &value); bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); bool CheckNoReturnAttr(const AttributeList &attr); bool CheckNoCallerSavedRegsAttr(const AttributeList &attr); bool checkStringLiteralArgumentAttr(const AttributeList &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); void checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceAttr::Spelling SemanticSpelling); void CheckAlignasUnderalignment(Decl *D); /// Adjust the calling convention of a method to be the ABI default if it /// wasn't specified explicitly. This handles method types formed from /// function type typedefs and typename template arguments. void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, SourceLocation Loc); // Check if there is an explicit attribute, but only look through parens. // The intent is to look for an attribute on the current declarator, but not // one that came from a typedef. bool hasExplicitCallingConv(QualType &T); /// Get the outermost AttributedType node that sets a calling convention. /// Valid types should not have multiple attributes with different CCs. const AttributedType *getCallingConvAttributedType(QualType T) const; /// Check whether a nullability type specifier can be added to the given /// type. /// /// \param type The type to which the nullability specifier will be /// added. On success, this type will be updated appropriately. /// /// \param nullability The nullability specifier to add. /// /// \param nullabilityLoc The location of the nullability specifier. /// /// \param isContextSensitive Whether this nullability specifier was /// written as a context-sensitive keyword (in an Objective-C /// method) or an Objective-C property attribute, rather than as an /// underscored type specifier. /// /// \param allowArrayTypes Whether to accept nullability specifiers on an /// array type (e.g., because it will decay to a pointer). /// /// \returns true if nullability cannot be applied, false otherwise. bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability, SourceLocation nullabilityLoc, bool isContextSensitive, bool allowArrayTypes); /// \brief Stmt attributes - this routine is the top level dispatcher. StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, SourceRange Range); void WarnConflictingTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); void CheckConflictingOverridingMethod(ObjCMethodDecl *Method, ObjCMethodDecl *Overridden, bool IsProtocolMethodDecl); /// WarnExactTypedMethods - This routine issues a warning if method /// implementation declaration matches exactly that of its declaration. void WarnExactTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); typedef llvm::SmallPtrSet SelectorSet; /// CheckImplementationIvars - This routine checks if the instance variables /// listed in the implelementation match those listed in the interface. void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, ObjCIvarDecl **Fields, unsigned nIvars, SourceLocation Loc); /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category \@implementation. void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, bool SynthesizeProperties); /// Diagnose any null-resettable synthesized setters. void diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl); /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in the class's \@implementation. void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, ObjCInterfaceDecl *IDecl); void DefaultSynthesizeProperties(Scope *S, Decl *D); /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is /// an ivar synthesized for 'Method' and 'Method' is a property accessor /// declared in class 'IFace'. bool IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, ObjCMethodDecl *Method, ObjCIvarDecl *IV); /// DiagnoseUnusedBackingIvarInAccessor - Issue an 'unused' warning if ivar which /// backs the property is not used in the property's accessor. void DiagnoseUnusedBackingIvarInAccessor(Scope *S, const ObjCImplementationDecl *ImplD); /// GetIvarBackingPropertyAccessor - If method is a property setter/getter and /// it property has a backing ivar, returns this ivar; otherwise, returns NULL. /// It also returns ivar's property on success. ObjCIvarDecl *GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method, const ObjCPropertyDecl *&PDecl) const; /// Called by ActOnProperty to handle \@property declarations in /// class extensions. ObjCPropertyDecl *HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, SourceLocation GetterNameLoc, Selector SetterSel, SourceLocation SetterNameLoc, const bool isReadWrite, unsigned &Attributes, const unsigned AttributesAsWritten, QualType T, TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind); /// Called by ActOnProperty and HandlePropertyInClassExtension to /// handle creating the ObjcPropertyDecl for a category or \@interface. ObjCPropertyDecl *CreatePropertyDecl(Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, SourceLocation GetterNameLoc, Selector SetterSel, SourceLocation SetterNameLoc, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, QualType T, TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, ObjCInterfaceDecl* IDecl); void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); void DiagnoseMissingDesignatedInitOverrides( const ObjCImplementationDecl *ImplD, const ObjCInterfaceDecl *IFD); void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); enum MethodMatchStrategy { MMS_loose, MMS_strict }; /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, const ObjCMethodDecl *PrevMethod, MethodMatchStrategy strategy = MMS_strict); /// MatchAllMethodDeclarations - Check methods declaraed in interface or /// or protocol against those declared in their implementations. void MatchAllMethodDeclarations(const SelectorSet &InsMap, const SelectorSet &ClsMap, SelectorSet &InsMapSeen, SelectorSet &ClsMapSeen, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool &IncompleteImpl, bool ImmediateClass, bool WarnCategoryMethodImpl=false); /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in /// category matches with those implemented in its primary class and /// warns each time an exact match is found. void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); /// \brief Add the given method to the list of globally-known methods. void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); private: /// AddMethodToGlobalPool - Add an instance or factory method to the global /// pool. See descriptoin of AddInstanceMethodToGlobalPool. void AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); /// LookupMethodInGlobalPool - Returns the instance or factory method and /// optionally warns if there are multiple signatures. ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass, bool instance); public: /// \brief - Returns instance or factory methods in global method pool for /// given selector. It checks the desired kind first, if none is found, and /// parameter checkTheOther is set, it then checks the other kind. If no such /// method or only one method is found, function returns false; otherwise, it /// returns true. bool CollectMultipleMethodsInGlobalPool(Selector Sel, SmallVectorImpl& Methods, bool InstanceFirst, bool CheckTheOther, const ObjCObjectType *TypeBound = nullptr); bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, SourceRange R, bool receiverIdOrClass, SmallVectorImpl& Methods); void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl &Methods, Selector Sel, SourceRange R, bool receiverIdOrClass); private: /// \brief - Returns a selector which best matches given argument list or /// nullptr if none could be found ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance, SmallVectorImpl& Methods); /// \brief Record the typo correction failure and return an empty correction. TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, bool RecordFailure = true) { if (RecordFailure) TypoCorrectionFailures[Typo].insert(TypoLoc); return TypoCorrection(); } public: /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate /// a selector with a method declaraation for purposes of typechecking /// messages sent to "id" (where the class of the object is unknown). void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { AddMethodToGlobalPool(Method, impl, /*instance*/true); } /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { AddMethodToGlobalPool(Method, impl, /*instance*/false); } /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global /// pool. void AddAnyMethodToGlobalPool(Decl *D); /// LookupInstanceMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, /*instance*/true); } /// LookupFactoryMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, /*instance*/false); } const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel, QualType ObjectType=QualType()); /// LookupImplementedMethodInGlobalPool - Returns the method which has an /// implementation. ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel); /// CollectIvarsToConstructOrDestruct - Collect those ivars which require /// initialization. void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, SmallVectorImpl &Ivars); //===--------------------------------------------------------------------===// // Statement Parsing Callbacks: SemaStmt.cpp. public: class FullExprArg { public: FullExprArg() : E(nullptr) { } FullExprArg(Sema &actions) : E(nullptr) { } ExprResult release() { return E; } Expr *get() const { return E; } Expr *operator->() { return E; } private: // FIXME: No need to make the entire Sema class a friend when it's just // Sema::MakeFullExpr that needs access to the constructor below. friend class Sema; explicit FullExprArg(Expr *expr) : E(expr) {} Expr *E; }; FullExprArg MakeFullExpr(Expr *Arg) { return MakeFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation()); } FullExprArg MakeFullExpr(Expr *Arg, SourceLocation CC) { return FullExprArg(ActOnFinishFullExpr(Arg, CC).get()); } FullExprArg MakeFullDiscardedValueExpr(Expr *Arg) { ExprResult FE = ActOnFinishFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation(), /*DiscardedValue*/ true); return FullExprArg(FE.get()); } StmtResult ActOnExprStmt(ExprResult Arg); StmtResult ActOnExprStmtError(); StmtResult ActOnNullStmt(SourceLocation SemiLoc, bool HasLeadingEmptyMacro = false); void ActOnStartOfCompoundStmt(); void ActOnFinishOfCompoundStmt(); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef Elts, bool isStmtExpr); /// \brief A RAII object to enter scope of a compound statement. class CompoundScopeRAII { public: CompoundScopeRAII(Sema &S): S(S) { S.ActOnStartOfCompoundStmt(); } ~CompoundScopeRAII() { S.ActOnFinishOfCompoundStmt(); } private: Sema &S; }; /// An RAII helper that pops function a function scope on exit. struct FunctionScopeRAII { Sema &S; bool Active; FunctionScopeRAII(Sema &S) : S(S), Active(true) {} ~FunctionScopeRAII() { if (Active) S.PopFunctionScopeInfo(); } void disable() { Active = false; } }; StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, SourceLocation StartLoc, SourceLocation EndLoc); void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); StmtResult ActOnForEachLValueExpr(Expr *E); StmtResult ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, SourceLocation DotDotDotLoc, Expr *RHSVal, SourceLocation ColonLoc); void ActOnCaseStmtBody(Stmt *CaseStmt, Stmt *SubStmt); StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope); StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt); StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, ArrayRef Attrs, Stmt *SubStmt); class ConditionResult; StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Stmt *InitStmt, ConditionResult Cond); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, Stmt *Body); StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, Expr *Cond, SourceLocation CondRParen); StmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *First, ConditionResult Second, FullExprArg Third, SourceLocation RParenLoc, Stmt *Body); ExprResult CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection); StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc); StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body); enum BuildForRangeKind { /// Initial building of a for-range statement. BFRK_Build, /// Instantiation or recovery rebuild of a for-range statement. Don't /// attempt any typo-correction. BFRK_Rebuild, /// Determining whether a for-range statement could be built. Avoid any /// unnecessary or irreversible actions. BFRK_Check }; StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *LoopVar, SourceLocation ColonLoc, Expr *Collection, SourceLocation RParenLoc, BuildForRangeKind Kind); StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *Begin, Stmt *End, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind); StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); StmtResult ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *TheDecl); StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr *DestExp); StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, unsigned NumParams); typedef std::pair CapturedParamNameType; void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, ArrayRef Params); StmtResult ActOnCapturedRegionEnd(Stmt *S); void ActOnCapturedRegionError(); RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, unsigned NumParams); VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, bool AllowParamOrMoveConstructible); bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, bool AllowParamOrMoveConstructible); StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, Scope *CurScope); StmtResult BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, Expr *AsmString, MultiExprArg Clobbers, SourceLocation RParenLoc); ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext); bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset, SourceLocation AsmLoc); ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, llvm::InlineAsmIdentifierInfo &Info, SourceLocation AsmLoc); StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef AsmToks, StringRef AsmString, unsigned NumOutputs, unsigned NumInputs, ArrayRef Constraints, ArrayRef Clobbers, ArrayRef Exprs, SourceLocation EndLoc); LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName, SourceLocation Location, bool AlwaysCreate); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, bool Invalid = false); Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, Decl *Parm, Stmt *Body); StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body); StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, MultiStmtArg Catch, Stmt *Finally); StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw); StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, Scope *CurScope); ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand); StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SynchExpr, Stmt *SynchBody); StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body); VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id); Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl, Stmt *HandlerBlock); StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef Handlers); StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ? SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler); StmtResult ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Stmt *Block); void ActOnStartSEHFinallyBlock(); void ActOnAbortSEHFinallyBlock(); StmtResult ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block); StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope); void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; /// \brief If it's a file scoped decl that must warn if not used, keep track /// of it. void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); void DiagnoseUnusedNestedTypedefs(const RecordDecl *D); void DiagnoseUnusedDecl(const NamedDecl *ND); /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null /// statement as a \p Body, and it is located on the same line. /// /// This helps prevent bugs due to typos, such as: /// if (condition); /// do_stuff(); void DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, unsigned DiagID); /// Warn if a for/while loop statement \p S, which is followed by /// \p PossibleBody, has a suspicious null statement as a body. void DiagnoseEmptyLoopBody(const Stmt *S, const Stmt *PossibleBody); /// Warn if a value is moved to itself. void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc); /// \brief Warn if we're implicitly casting from a _Nullable pointer type to a /// _Nonnull one. void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, SourceLocation Loc); /// Warn when implicitly casting 0 to nullptr. void diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E); ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { return DelayedDiagnostics.push(pool); } void PopParsingDeclaration(ParsingDeclState state, Decl *decl); typedef ProcessingContextState ParsingClassState; ParsingClassState PushParsingClass() { return DelayedDiagnostics.pushUndelayed(); } void PopParsingClass(ParsingClassState state) { DelayedDiagnostics.popUndelayed(state); } void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess); bool makeUnavailableInSystemHeader(SourceLocation loc, UnavailableAttr::ImplicitReason reason); /// \brief Issue any -Wunguarded-availability warnings in \c FD void DiagnoseUnguardedAvailabilityViolations(Decl *FD); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass=nullptr, bool ObjCPropertyAccess=false); void NoteDeletedFunction(FunctionDecl *FD); void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD); std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ArrayRef Args); void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, bool IsDecltype = false); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, bool IsDecltype = false); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); ExprResult TransformToPotentiallyEvaluated(Expr *E); ExprResult HandleExprEvaluationContextForTypeof(Expr *E); ExprResult ActOnConstantExpression(ExprResult Res); // Functions for marking a declaration referenced. These functions also // contain the relevant logic for marking if a reference to a function or // variable is an odr-use (in the C++11 sense). There are separate variants // for expressions referring to a decl; these exist because odr-use marking // needs to be delayed for some constant variables when we build one of the // named expressions. // // MightBeOdrUse indicates whether the use could possibly be an odr-use, and // should usually be true. This only needs to be set to false if the lack of // odr-use cannot be determined from the current context (for instance, // because the name denotes a virtual function and was written without an // explicit nested-name-specifier). void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse = true); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E); void MarkMemberReferenced(MemberExpr *E); void UpdateMarkingForLValueToRValue(Expr *E); void CleanupVarDeclMarking(); enum TryCaptureKind { TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef }; /// \brief Try to capture the given variable. /// /// \param Var The variable to capture. /// /// \param Loc The location at which the capture occurs. /// /// \param Kind The kind of capture, which may be implicit (for either a /// block or a lambda), or explicit by-value or by-reference (for a lambda). /// /// \param EllipsisLoc The location of the ellipsis, if one is provided in /// an explicit lambda capture. /// /// \param BuildAndDiagnose Whether we are actually supposed to add the /// captures or diagnose errors. If false, this routine merely check whether /// the capture can occur without performing the capture itself or complaining /// if the variable cannot be captured. /// /// \param CaptureType Will be set to the type of the field used to capture /// this variable in the innermost block or lambda. Only valid when the /// variable can be captured. /// /// \param DeclRefType Will be set to the type of a reference to the capture /// from within the current scope. Only valid when the variable can be /// captured. /// /// \param FunctionScopeIndexToStopAt If non-null, it points to the index /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. /// This is useful when enclosing lambdas must speculatively capture /// variables that may or may not be used in certain specializations of /// a nested generic lambda. /// /// \returns true if an error occurred (i.e., the variable cannot be /// captured) and false if the capture succeeded. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt); /// \brief Try to capture the given variable. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); /// \brief Checks if the variable must be captured. bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); /// \brief Given a variable, determine the type that a reference to that /// variable will have in the given scope. QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); /// Mark all of the declarations referenced within a particular AST node as /// referenced. Used when template instantiation instantiates a non-dependent /// type -- entities referenced by the type are now referenced. void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); void MarkDeclarationsReferencedInExpr(Expr *E, bool SkipLocalVariables = false); /// \brief Try to recover by turning the given expression into a /// call. Returns true if recovery was attempted or an error was /// emitted; this may also leave the ExprResult invalid. bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain = false, bool (*IsPlausibleResult)(QualType) = nullptr); /// \brief Figure out if an expression could be turned into a call. bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, UnresolvedSetImpl &NonTemplateOverloads); /// \brief Conditionally issue a diagnostic based on the current /// evaluation context. /// /// \param Statement If Statement is non-null, delay reporting the /// diagnostic until the function body is parsed, and then do a basic /// reachability analysis to determine if the statement is reachable. /// If it is unreachable, the diagnostic will not be emitted. bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD); // Primary Expressions. SourceRange getExprRange(Expr *E) const; ExprResult ActOnIdExpression( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, std::unique_ptr CCC = nullptr, bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr); void DecomposeUnqualifiedId(const UnqualifiedId &Id, TemplateArgumentListInfo &Buffer, DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *&TemplateArgs); bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, std::unique_ptr CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, ArrayRef Args = None, TypoExpr **Out = nullptr); ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S, IdentifierInfo *II, bool AllowBuiltinCreation=false); ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS = nullptr); ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS = nullptr, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr); ExprResult BuildAnonymousStructUnionMemberReference( const CXXScopeSpec &SS, SourceLocation nameLoc, IndirectFieldDecl *indirectField, DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none), Expr *baseObjectExpr = nullptr, SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S); ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, bool IsDefiniteInstance, const Scope *S); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI = nullptr); ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, bool AcceptInvalidDecl = false); ExprResult BuildDeclarationNameExpr( const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr, bool AcceptInvalidDecl = false); ExprResult BuildLiteralOperatorCall(LookupResult &R, DeclarationNameInfo &SuffixInfo, ArrayRef Args, SourceLocation LitEndLoc, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); ExprResult BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentType IT); ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = nullptr); ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E); ExprResult ActOnParenListExpr(SourceLocation L, SourceLocation R, MultiExprArg Val); /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). ExprResult ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope = nullptr); ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef ArgTypes, ArrayRef ArgExprs); ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef Types, ArrayRef Exprs); // Binary/Unary Operators. 'Tok' is the token for the operator. ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *InputExpr); ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *Input); ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, Expr *Input); QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc); ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, SourceRange R); ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind); ExprResult ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, bool IsType, void *TyOrEx, SourceRange ArgRange); ExprResult CheckPlaceholderExpr(Expr *E); bool CheckVecStepExpr(Expr *E); bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, UnaryExprOrTypeTrait ExprKind); ExprResult ActOnSizeofParameterPackExpr(Scope *S, SourceLocation OpLoc, IdentifierInfo &Name, SourceLocation NameLoc, SourceLocation RParenLoc); ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input); ExprResult ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBLoc); // This struct is for use by ActOnMemberAccess to allow // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after // changing the access operator from a '.' to a '->' (to see if that is the // change needed to fix an error about an unknown member, e.g. when the class // defines a custom operator->). struct ActOnMemberAccessExtraArgs { Scope *S; UnqualifiedId &Id; Decl *ObjCImpDecl; }; ExprResult BuildMemberReferenceExpr( Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, FieldDecl *Field, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo); ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, const CXXScopeSpec &SS, const LookupResult &R); ExprResult ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Member, Decl *ObjCImpDecl); void ActOnDefaultCtorInitializers(Decl *CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, ArrayRef Args, SourceLocation RParenLoc, bool ExecConfig = false); void CheckStaticArrayArgument(SourceLocation CallLoc, ParmVarDecl *Param, const Expr *ArgExpr); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr, bool IsExecConfig = false); ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, ArrayRef Arg, SourceLocation RParenLoc, Expr *Config = nullptr, bool IsExecConfig = false); ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc); ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *CastExpr); ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, Expr *Op); CastKind PrepareScalarCast(ExprResult &src, QualType destType); /// \brief Build an altivec or OpenCL literal. ExprResult BuildVectorLiteral(SourceLocation LParenLoc, SourceLocation RParenLoc, Expr *E, TypeSourceInfo *TInfo); ExprResult MaybeConvertParenListExprToParenExpr(Scope *S, Expr *ME); ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc, Expr *InitExpr); ExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceLocation RParenLoc, Expr *LiteralExpr); ExprResult ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc); ExprResult ActOnDesignatedInitializer(Designation &Desig, SourceLocation Loc, bool GNUSyntax, ExprResult Init); private: static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind); public: ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr); ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); void DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc); /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, SourceLocation ColonLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr); /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl); void ActOnStartStmtExpr(); ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc); // "({..})" void ActOnStmtExprError(); // __builtin_offsetof(type, identifier(.identifier|[expr])*) struct OffsetOfComponent { SourceLocation LocStart, LocEnd; bool isBrackets; // true if [expr], false if .ident union { IdentifierInfo *IdentInfo; Expr *E; } U; }; /// __builtin_offsetof(type, a.b[123][456].c) ExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, TypeSourceInfo *TInfo, ArrayRef Components, SourceLocation RParenLoc); ExprResult ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, ParsedType ParsedArgTy, ArrayRef Components, SourceLocation RParenLoc); // __builtin_choose_expr(constExpr, expr1, expr2) ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr, SourceLocation RPLoc); // __builtin_va_arg(expr, type) ExprResult ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, SourceLocation RPLoc); ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, TypeSourceInfo *TInfo, SourceLocation RPLoc); // __null ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); bool CheckCaseExpression(Expr *E); /// \brief Describes the result of an "if-exists" condition check. enum IfExistsResult { /// \brief The symbol exists. IER_Exists, /// \brief The symbol does not exist. IER_DoesNotExist, /// \brief The name is a dependent name, so the results will differ /// from one instantiation to the next. IER_Dependent, /// \brief An error occurred. IER_Error }; IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo); IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name); StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, NestedNameSpecifierLoc QualifierLoc, DeclarationNameInfo NameInfo, Stmt *Nested); StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name, Stmt *Nested); //===------------------------- "Block" Extension ------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is /// started. void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); /// ActOnBlockArguments - This callback allows processing of block arguments. /// If there are no arguments, this is still invoked. void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, Scope *CurScope); /// ActOnBlockError - If there is an error parsing a block, this callback /// is invoked to pop the information about the block from the action impl. void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, Scope *CurScope); //===---------------------------- Clang Extensions ----------------------===// /// __builtin_convertvector(...) ExprResult ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc); //===---------------------------- OpenCL Features -----------------------===// /// __builtin_astype(...) ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc); //===---------------------------- C++ Features --------------------------===// // Act on C++ namespaces Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc, SourceLocation NamespaceLoc, SourceLocation IdentLoc, IdentifierInfo *Ident, SourceLocation LBrace, AttributeList *AttrList, UsingDirectiveDecl * &UsingDecl); void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); NamespaceDecl *getStdNamespace() const; NamespaceDecl *getOrCreateStdNamespace(); NamespaceDecl *lookupStdExperimentalNamespace(); CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; /// \brief Tests whether Ty is an instance of std::initializer_list and, if /// it is and Element is not NULL, assigns the element type to Element. bool isStdInitializerList(QualType Ty, QualType *Element); /// \brief Looks for the std::initializer_list template and instantiates it /// with Element, or emits an error if it's not found. /// /// \returns The instantiated template, or null on error. QualType BuildStdInitializerList(QualType Element, SourceLocation Loc); /// \brief Determine whether Ctor is an initializer-list constructor, as /// defined in [dcl.init.list]p2. bool isInitListConstructor(const FunctionDecl *Ctor); Decl *ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList); void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); Decl *ActOnNamespaceAliasDef(Scope *CurScope, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident); void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, const LookupResult &PreviousDecls, UsingShadowDecl *&PrevShadow); UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, NamedDecl *Target, UsingShadowDecl *PrevDecl); bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, bool HasTypenameKeyword, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Previous); bool CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, SourceLocation NameLoc); NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc, AttributeList *AttrList, bool IsInstantiation); NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom, ArrayRef Expansions); bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); /// Given a derived-class using shadow declaration for a constructor and the /// correspnding base class constructor, find or create the implicit /// synthesized derived class constructor to use for this initialization. CXXConstructorDecl * findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *BaseCtor, ConstructorUsingShadowDecl *DerivedShadow); Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation TypenameLoc, CXXScopeSpec &SS, UnqualifiedId &Name, SourceLocation EllipsisLoc, AttributeList *AttrList); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, AttributeList *AttrList, TypeResult Type, Decl *DeclFromDeclSpec); /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. /// /// \param ConstructKind - a CXXConstructExpr::ConstructionKind ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); /// Build a CXXConstructExpr whose constructor has already been resolved if /// it denotes an inherited constructor. ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); // FIXME: Can we remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field); /// Instantiate or parse a C++ default argument expression as necessary. /// Return true on error. bool CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating /// the default expr if needed. ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); /// FinalizeVarWithDestructor - Prepare for calling destructor on the /// constructed variable. void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); /// \brief Helper class that collects exception specifications for /// implicitly-declared special member functions. class ImplicitExceptionSpecification { // Pointer to allow copying Sema *Self; // We order exception specifications thus: // noexcept is the most restrictive, but is only used in C++11. // throw() comes next. // Then a throw(collected exceptions) // Finally no specification, which is expressed as noexcept(false). // throw(...) is used instead if any called function uses it. ExceptionSpecificationType ComputedEST; llvm::SmallPtrSet ExceptionsSeen; SmallVector Exceptions; void ClearExceptions() { ExceptionsSeen.clear(); Exceptions.clear(); } public: explicit ImplicitExceptionSpecification(Sema &Self) : Self(&Self), ComputedEST(EST_BasicNoexcept) { if (!Self.getLangOpts().CPlusPlus11) ComputedEST = EST_DynamicNone; } /// \brief Get the computed exception specification type. ExceptionSpecificationType getExceptionSpecType() const { assert(ComputedEST != EST_ComputedNoexcept && "noexcept(expr) should not be a possible result"); return ComputedEST; } /// \brief The number of exceptions in the exception specification. unsigned size() const { return Exceptions.size(); } /// \brief The set of exceptions in the exception specification. const QualType *data() const { return Exceptions.data(); } /// \brief Integrate another called method into the collected data. void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method); /// \brief Integrate an invoked expression into the collected data. void CalledExpr(Expr *E); /// \brief Overwrite an EPI's exception specification with this /// computed exception specification. FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const { FunctionProtoType::ExceptionSpecInfo ESI; ESI.Type = getExceptionSpecType(); if (ESI.Type == EST_Dynamic) { ESI.Exceptions = Exceptions; } else if (ESI.Type == EST_None) { /// C++11 [except.spec]p14: /// The exception-specification is noexcept(false) if the set of /// potential exceptions of the special member function contains "any" ESI.Type = EST_ComputedNoexcept; ESI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(), tok::kw_false).get(); } return ESI; } }; /// \brief Determine what sort of exception specification a defaulted /// copy constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted /// default constructor of a class will have, and whether the parameter /// will be const. ImplicitExceptionSpecification ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defautled /// copy assignment operator of a class will have, and whether the /// parameter will be const. ImplicitExceptionSpecification ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted move /// constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted move /// assignment operator of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted /// destructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification an inheriting /// constructor of a class will have. ImplicitExceptionSpecification ComputeInheritingCtorExceptionSpec(SourceLocation Loc, CXXConstructorDecl *CD); /// \brief Evaluate the implicit exception specification for a defaulted /// special member function. void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); /// \brief Check the given exception-specification and update the /// exception specification information with the results. void checkExceptionSpecification(bool IsTopLevel, ExceptionSpecificationType EST, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr, SmallVectorImpl &Exceptions, FunctionProtoType::ExceptionSpecInfo &ESI); /// \brief Determine if we're in a case where we need to (incorrectly) eagerly /// parse an exception specification to work around a libstdc++ bug. bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D); /// \brief Add an exception-specification to the given member function /// (or member function template). The exception-specification was parsed /// after the method itself was declared. void actOnDelayedExceptionSpecification(Decl *Method, ExceptionSpecificationType EST, SourceRange SpecificationRange, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr); class InheritedConstructorInfo; /// \brief Determine if a special member function should have a deleted /// definition when it is defaulted. bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, InheritedConstructorInfo *ICI = nullptr, bool Diagnose = false); /// \brief Declare the implicit default constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// default constructor will be added. /// /// \returns The implicitly-declared default constructor. CXXConstructorDecl *DeclareImplicitDefaultConstructor( CXXRecordDecl *ClassDecl); /// DefineImplicitDefaultConstructor - Checks for feasibility of /// defining this constructor as the default constructor. void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// \brief Declare the implicit destructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// destructor will be added. /// /// \returns The implicitly-declared destructor. CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl); /// DefineImplicitDestructor - Checks for feasibility of /// defining this destructor as the default destructor. void DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor); /// \brief Build an exception spec for destructors that don't have one. /// /// C++11 says that user-defined destructors with no exception spec get one /// that looks as if the destructor was implicitly declared. void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, CXXDestructorDecl *Destructor); /// \brief Define the specified inheriting constructor. void DefineInheritingConstructor(SourceLocation UseLoc, CXXConstructorDecl *Constructor); /// \brief Declare the implicit copy constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy constructor will be added. /// /// \returns The implicitly-declared copy constructor. CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl); /// DefineImplicitCopyConstructor - Checks for feasibility of /// defining this constructor as the copy constructor. void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// \brief Declare the implicit move constructor for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move constructor will be added. /// /// \returns The implicitly-declared move constructor, or NULL if it wasn't /// declared. CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl); /// DefineImplicitMoveConstructor - Checks for feasibility of /// defining this constructor as the move constructor. void DefineImplicitMoveConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// \brief Declare the implicit copy assignment operator for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy assignment operator will be added. /// /// \returns The implicitly-declared copy assignment operator. CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); /// \brief Defines an implicitly-declared copy assignment operator. void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); /// \brief Declare the implicit move assignment operator for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move assignment operator will be added. /// /// \returns The implicitly-declared move assignment operator, or NULL if it /// wasn't declared. CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl); /// \brief Defines an implicitly-declared move assignment operator. void DefineImplicitMoveAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); /// \brief Force the declaration of any implicitly-declared members of this /// class. void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); /// \brief Check a completed declaration of an implicit special member. void CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD); /// \brief Determine whether the given function is an implicitly-deleted /// special member function. bool isImplicitlyDeleted(FunctionDecl *FD); /// \brief Check whether 'this' shows up in the type of a static member /// function after the (naturally empty) cv-qualifier-seq would be. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); /// \brief Whether this' shows up in the exception specification of a static /// member function. bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); /// \brief Check whether 'this' shows up in the attributes of the given /// static member function. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method); /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise /// it simply returns the passed in expression. ExprResult MaybeBindToTemporary(Expr *E); bool CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, SourceLocation Loc, SmallVectorImpl &ConvertedArgs, bool AllowExplicit = false, bool IsListInitialization = false); ParsedType getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo &Name); ParsedType getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext); ParsedType getDestructorTypeForDecltype(const DeclSpec &DS, ParsedType ObjectType); // Checks that reinterpret casts don't have undefined behavior. void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, bool IsDereference, SourceRange Range); /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, Declarator &D, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, Expr *E, SourceLocation RParenLoc); ExprResult BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, TypeSourceInfo *Ty, Expr *E, SourceRange AngleBrackets, SourceRange Parens); ExprResult BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc); ExprResult BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc); /// ActOnCXXTypeid - Parse typeid( something ). ExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc); ExprResult BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc); ExprResult BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc); /// ActOnCXXUuidof - Parse __uuidof( something ). ExprResult ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc); /// \brief Handle a C++1z fold-expression: ( expr op ... op expr ). ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, tok::TokenKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc); ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc); ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, BinaryOperatorKind Operator); //// ActOnCXXThis - Parse 'this' pointer. ExprResult ActOnCXXThis(SourceLocation loc); /// \brief Try to retrieve the type of the 'this' pointer. /// /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. QualType getCurrentThisType(); /// \brief When non-NULL, the C++ 'this' expression is allowed despite the /// current context not being a non-static member function. In such cases, /// this provides the type used for 'this'. QualType CXXThisTypeOverride; /// \brief RAII object used to temporarily allow the C++ 'this' expression /// to be used, with the given qualifiers on the current class type. class CXXThisScopeRAII { Sema &S; QualType OldCXXThisTypeOverride; bool Enabled; public: /// \brief Introduce a new scope where 'this' may be allowed (when enabled), /// using the given declaration (which is either a class template or a /// class) along with the given qualifiers. /// along with the qualifiers placed on '*this'. CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, bool Enabled = true); ~CXXThisScopeRAII(); }; /// \brief Make sure the value of 'this' is actually available in the current /// context, if it is a potentially evaluated context. /// /// \param Loc The location at which the capture of 'this' occurs. /// /// \param Explicit Whether 'this' is explicitly captured in a lambda /// capture list. /// /// \param FunctionScopeIndexToStopAt If non-null, it points to the index /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. /// This is useful when enclosing lambdas must speculatively capture /// 'this' that may or may not be used in certain specializations of /// a nested generic lambda (depending on whether the name resolves to /// a non-static member function or a static function). /// \return returns 'true' if failed, 'false' if success. bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false, bool BuildAndDiagnose = true, const unsigned *const FunctionScopeIndexToStopAt = nullptr, bool ByCopy = false); /// \brief Determine whether the given type is the type of *this that is used /// outside of the body of a member function for a type that is currently /// being defined. bool isThisOutsideMemberFunctionBody(QualType BaseType); /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals. ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); ExprResult ActOnObjCAvailabilityCheckExpr(llvm::ArrayRef AvailSpecs, SourceLocation AtLoc, SourceLocation RParen); /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); //// ActOnCXXThrow - Parse throw expressions. ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope); bool CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ThrowTy, Expr *E); /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenLoc, MultiExprArg Exprs, SourceLocation RParenLoc); ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, MultiExprArg Exprs, SourceLocation RParenLoc); /// ActOnCXXNew - Parsed a C++ 'new' expression. ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer); ExprResult BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, Expr *ArraySize, SourceRange DirectInitRange, Expr *Initializer); bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R); bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool UseGlobal, QualType AllocType, bool IsArray, bool &PassAlignment, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete); void DeclareGlobalNewDelete(); void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, ArrayRef Params); bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator, bool Diagnose = true); FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, bool Overaligned, DeclarationName Name); FunctionDecl *FindDeallocationFunctionForDestructor(SourceLocation StartLoc, CXXRecordDecl *RD); /// ActOnCXXDelete - Parsed a C++ 'delete' expression ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *Operand); void CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc); ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, Expr *Operand, SourceLocation RParen); ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen); /// \brief Parsed one of the type trait support pseudo-functions. ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc); ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc); /// ActOnArrayTypeTrait - Parsed one of the binary type trait support /// pseudo-functions. ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, ParsedType LhsTy, Expr *DimExpr, SourceLocation RParen); ExprResult BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, TypeSourceInfo *TSInfo, Expr *DimExpr, SourceLocation RParen); /// ActOnExpressionTrait - Parsed one of the unary type trait support /// pseudo-functions. ExprResult ActOnExpressionTrait(ExpressionTrait OET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen); ExprResult BuildExpressionTrait(ExpressionTrait OET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen); ExprResult ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, bool &MayBePseudoDestructor); ExprResult BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation TildeLoc, const DeclSpec& DS); /// MaybeCreateExprWithCleanups - If the current full-expression /// requires any cleanups, surround it with a ExprWithCleanups node. /// Otherwise, just returns the passed-in expression. Expr *MaybeCreateExprWithCleanups(Expr *SubExpr); Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt); ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr); MaterializeTemporaryExpr * CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary, bool BoundToLvalueReference); ExprResult ActOnFinishFullExpr(Expr *Expr) { return ActOnFinishFullExpr(Expr, Expr ? Expr->getExprLoc() : SourceLocation()); } ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC, bool DiscardedValue = false, bool IsConstexpr = false, bool IsLambdaInitCaptureInitializer = false); StmtResult ActOnFinishFullStmt(Stmt *Stmt); // Marks SS invalid if it represents an incomplete type. bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); DeclContext *computeDeclContext(QualType T); DeclContext *computeDeclContext(const CXXScopeSpec &SS, bool EnteringContext = false); bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); /// \brief The parser has parsed a global nested-name-specifier '::'. /// /// \param CCLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS); /// \brief The parser has parsed a '__super' nested-name-specifier. /// /// \param SuperLoc The location of the '__super' keyword. /// /// \param ColonColonLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc, SourceLocation ColonColonLoc, CXXScopeSpec &SS); bool isAcceptableNestedNameSpecifier(const NamedDecl *SD, bool *CanCorrect = nullptr); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); /// \brief Keeps information about an identifier in a nested-name-spec. /// struct NestedNameSpecInfo { /// \brief The type of the object, if we're parsing nested-name-specifier in /// a member access expression. ParsedType ObjectType; /// \brief The identifier preceding the '::'. IdentifierInfo *Identifier; /// \brief The location of the identifier. SourceLocation IdentifierLoc; /// \brief The location of the '::'. SourceLocation CCLoc; /// \brief Creates info object for the most typical case. NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, SourceLocation ColonColonLoc, ParsedType ObjectType = ParsedType()) : ObjectType(ObjectType), Identifier(II), IdentifierLoc(IdLoc), CCLoc(ColonColonLoc) { } NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, SourceLocation ColonColonLoc, QualType ObjectType) : ObjectType(ParsedType::make(ObjectType)), Identifier(II), IdentifierLoc(IdLoc), CCLoc(ColonColonLoc) { } }; bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, NestedNameSpecInfo &IdInfo); bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, bool *IsCorrectedToColon = nullptr, bool OnlyNamespace = false); /// \brief The parser has parsed a nested-name-specifier 'identifier::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param IdInfo Parser information about an identifier in the /// nested-name-spec. /// /// \param EnteringContext Whether we're entering the context nominated by /// this nested-name-specifier. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). /// /// \param ErrorRecoveryLookup If true, then this method is called to improve /// error recovery. In this case do not emit error message. /// /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':' /// are allowed. The bool value pointed by this parameter is set to 'true' /// if the identifier is treated as if it was followed by ':', not '::'. /// /// \param OnlyNamespace If true, only considers namespaces in lookup. /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, bool ErrorRecoveryLookup = false, bool *IsCorrectedToColon = nullptr, bool OnlyNamespace = false); ExprResult ActOnDecltypeExpression(Expr *E); bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, const DeclSpec &DS, SourceLocation ColonColonLoc); bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, NestedNameSpecInfo &IdInfo, bool EnteringContext); /// \brief The parser has parsed a nested-name-specifier /// 'template[opt] template-name < template-args >::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). /// /// \param TemplateKWLoc the location of the 'template' keyword, if any. /// \param TemplateName the template name. /// \param TemplateNameLoc The location of the template name. /// \param LAngleLoc The location of the opening angle bracket ('<'). /// \param TemplateArgs The template arguments. /// \param RAngleLoc The location of the closing angle bracket ('>'). /// \param CCLoc The location of the '::'. /// /// \param EnteringContext Whether we're entering the context of the /// nested-name-specifier. /// /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateName, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, SourceLocation CCLoc, bool EnteringContext); /// \brief Given a C++ nested-name-specifier, produce an annotation value /// that the parser can use later to reconstruct the given /// nested-name-specifier. /// /// \param SS A nested-name-specifier. /// /// \returns A pointer containing all of the information in the /// nested-name-specifier \p SS. void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); /// \brief Given an annotation pointer for a nested-name-specifier, restore /// the nested-name-specifier structure. /// /// \param Annotation The annotation pointer, produced by /// \c SaveNestedNameSpecifierAnnotation(). /// /// \param AnnotationRange The source range corresponding to the annotation. /// /// \param SS The nested-name-specifier that will be updated with the contents /// of the annotation pointer. void RestoreNestedNameSpecifierAnnotation(void *Annotation, SourceRange AnnotationRange, CXXScopeSpec &SS); bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. /// Used to indicate that names should revert to being looked up in the /// defining scope. void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an /// initializer for the declaration 'Dcl'. /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a /// static data member of class X, names should be looked up in the scope of /// class X. void ActOnCXXEnterDeclInitializer(Scope *S, Decl *Dcl); /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an /// initializer for the declaration 'Dcl'. void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); /// \brief Create a new lambda closure type. CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, bool KnownDependent, LambdaCaptureDefault CaptureDefault); /// \brief Start the definition of a lambda expression. CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, ArrayRef Params, bool IsConstexprSpecified); /// \brief Endow the lambda scope info with the relevant properties. void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, bool Mutable); /// \brief Perform initialization analysis of the init-capture and perform /// any implicit conversions such as an lvalue-to-rvalue conversion if /// not being used to initialize a reference. ParsedType actOnLambdaInitCaptureInitialization( SourceLocation Loc, bool ByRef, IdentifierInfo *Id, LambdaCaptureInitKind InitKind, Expr *&Init) { return ParsedType::make(buildLambdaInitCaptureInitialization( Loc, ByRef, Id, InitKind != LambdaCaptureInitKind::CopyInit, Init)); } QualType buildLambdaInitCaptureInitialization(SourceLocation Loc, bool ByRef, IdentifierInfo *Id, bool DirectInit, Expr *&Init); /// \brief Create a dummy variable within the declcontext of the lambda's /// call operator, for name lookup purposes for a lambda init capture. /// /// CodeGen handles emission of lambda captures, ignoring these dummy /// variables appropriately. VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc, QualType InitCaptureType, IdentifierInfo *Id, unsigned InitStyle, Expr *Init); /// \brief Build the implicit field for an init-capture. FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var); /// \brief Note that we have finished the explicit captures for the /// given lambda. void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); /// \brief Introduce the lambda parameters into scope. void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope); /// \brief Deduce a block or lambda's return type based on the return /// statements present in the body. void deduceClosureReturnType(sema::CapturingScopeInfo &CSI); /// ActOnStartOfLambdaDefinition - This is called just before we start /// parsing the body of a lambda; it analyzes the explicit captures and /// arguments, and sets up various data-structures for the body of the /// lambda. void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope); /// ActOnLambdaError - If there is an error parsing a lambda, this callback /// is invoked to pop the information about the lambda. void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, bool IsInstantiation = false); /// ActOnLambdaExpr - This is called when the body of a lambda expression /// was successfully completed. ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope); /// \brief Does copying/destroying the captured variable have side effects? bool CaptureHasSideEffects(const sema::LambdaScopeInfo::Capture &From); /// \brief Diagnose if an explicit lambda capture is unused. void DiagnoseUnusedLambdaCapture(const sema::LambdaScopeInfo::Capture &From); /// \brief Complete a lambda-expression having processed and attached the /// lambda body. ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, sema::LambdaScopeInfo *LSI); /// \brief Define the "body" of the conversion from a lambda object to a /// function pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills /// in the initialization expression needed to copy the lambda object into /// the block, and IR generation actually generates the real body of the /// block pointer conversion. void DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLoc, CXXConversionDecl *Conv); /// \brief Define the "body" of the conversion from a lambda object to a /// block pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills /// in the initialization expression needed to copy the lambda object into /// the block, and IR generation actually generates the real body of the /// block pointer conversion. void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc, CXXConversionDecl *Conv); ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation, SourceLocation ConvLocation, CXXConversionDecl *Conv, Expr *Src); // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef Strings); ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S); /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the /// numeric literal expression. Type of the expression will be "NSNumber *" /// or "id" if NSNumber is unavailable. ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number); ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc, bool Value); ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements); /// BuildObjCBoxedExpr - builds an ObjCBoxedExpr AST node for the /// '@' prefixed parenthesized expression. The type of the expression will /// either be "NSNumber *", "NSString *" or "NSValue *" depending on the type /// of ValueType, which is allowed to be a built-in numeric type, "char *", /// "const char *" or C structure with attribute 'objc_boxable'. ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr); ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Expr *IndexExpr, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod); ExprResult BuildObjCDictionaryLiteral(SourceRange SR, MutableArrayRef Elements); ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc, TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc); ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, CXXConversionDecl *Method, bool HadMultipleCandidates); ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc); /// ParseObjCSelectorExpression - Build selector expression for \@selector ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, SourceLocation SelLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, bool WarnMultipleSelectors); /// ParseObjCProtocolExpression - Build protocol expression for \@protocol ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, SourceLocation AtLoc, SourceLocation ProtoLoc, SourceLocation LParenLoc, SourceLocation ProtoIdLoc, SourceLocation RParenLoc); //===--------------------------------------------------------------------===// // C++ Declarations // Decl *ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, Expr *LangStr, SourceLocation LBraceLoc); Decl *ActOnFinishLinkageSpecification(Scope *S, Decl *LinkageSpec, SourceLocation RBraceLoc); //===--------------------------------------------------------------------===// // C++ Classes // bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = nullptr); bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS); bool ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, SourceLocation ColonLoc, AttributeList *Attrs = nullptr); NamedDecl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BitfieldWidth, const VirtSpecifiers &VS, InClassInitStyle InitStyle); void ActOnStartCXXInClassMemberInitializer(); void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc, Expr *Init); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, SourceLocation LParenLoc, ArrayRef Args, SourceLocation RParenLoc, SourceLocation EllipsisLoc); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *InitList, SourceLocation EllipsisLoc); MemInitResult BuildMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc); MemInitResult BuildMemberInitializer(ValueDecl *Member, Expr *Init, SourceLocation IdLoc); MemInitResult BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc); MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, CXXRecordDecl *ClassDecl); bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, CXXCtorInitializer *Initializer); bool SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, ArrayRef Initializers = None); void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as /// referenced. void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, CXXRecordDecl *Record); /// \brief The list of classes whose vtables have been used within /// this translation unit, and the source locations at which the /// first use occurred. typedef std::pair VTableUse; /// \brief The list of vtables that are required but have not yet been /// materialized. SmallVector VTableUses; /// \brief The set of classes whose vtables have been used within /// this translation unit, and a bit that will be true if the vtable is /// required to be emitted (otherwise, it should be emitted only if needed /// by code generation). llvm::DenseMap VTablesUsed; /// \brief Load any externally-stored vtable uses. void LoadExternalVTableUses(); /// \brief Note that the vtable for the given class was used at the /// given location. void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired = false); /// \brief Mark the exception specifications of all virtual member functions /// in the given class as needed. void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, const CXXRecordDecl *RD); /// MarkVirtualMembersReferenced - Will mark all members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD); /// \brief Define all of the vtables that have been used in this /// translation unit and reference any virtual members used by those /// vtables. /// /// \returns true if any work was done, false otherwise. bool DefineUsedVTables(); void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); void ActOnMemInitializers(Decl *ConstructorDecl, SourceLocation ColonLoc, ArrayRef MemInits, bool AnyErrors); /// \brief Check class-level dllimport/dllexport attribute. The caller must /// ensure that referenceDLLExportedClassMethods is called some point later /// when all outer classes of Class are complete. void checkClassLevelDLLAttribute(CXXRecordDecl *Class); void referenceDLLExportedClassMethods(); void propagateDLLAttrToBaseClassTemplate( CXXRecordDecl *Class, Attr *ClassAttr, ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc); void CheckCompletedCXXClass(CXXRecordDecl *Record); void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList); void ActOnFinishCXXMemberDecls(); void ActOnFinishCXXNonNestedClass(Decl *D); void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); unsigned ActOnReenterTemplateScope(Scope *S, Decl *Template); void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnFinishDelayedMemberInitializers(Decl *Record); void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, CachedTokens &Toks); void UnmarkAsLateParsedTemplate(FunctionDecl *FD); bool IsInsideALocalClassWithinATemplateFunction(); Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr, SourceLocation RParenLoc); Decl *BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, StringLiteral *AssertMessageExpr, SourceLocation RParenLoc, bool Failed); FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart, SourceLocation FriendLoc, TypeSourceInfo *TSInfo); Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TemplateParams); NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParams); QualType CheckConstructorDeclarator(Declarator &D, QualType R, StorageClass& SC); void CheckConstructor(CXXConstructorDecl *Constructor); QualType CheckDestructorDeclarator(Declarator &D, QualType R, StorageClass& SC); bool CheckDestructor(CXXDestructorDecl *Destructor); void CheckConversionDeclarator(Declarator &D, QualType &R, StorageClass& SC); Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); void CheckDeductionGuideDeclarator(Declarator &D, QualType &R, StorageClass &SC); void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD); void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD); void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD, const FunctionProtoType *T); void CheckDelayedMemberExceptionSpecs(); //===--------------------------------------------------------------------===// // C++ Derived Classes // /// ActOnBaseSpecifier - Parsed a base specifier CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc); BaseResult ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, ParsedAttributes &Attrs, bool Virtual, AccessSpecifier Access, ParsedType basetype, SourceLocation BaseLoc, SourceLocation EllipsisLoc); bool AttachBaseSpecifiers(CXXRecordDecl *Class, MutableArrayRef Bases); void ActOnBaseSpecifiers(Decl *ClassDecl, MutableArrayRef Bases); bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base); bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, CXXBasePaths &Paths); // FIXME: I don't like this name. void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, CXXCastPath *BasePath = nullptr, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, CXXCastPath *BasePath, bool IgnoreAccess = false); std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionReturnType - Checks whether the return types are /// covariant, according to C++ [class.virtual]p5. bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionExceptionSpec - Checks whether the exception /// spec is a subset of base spec. bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old); bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); /// CheckOverrideControl - Check C++11 override control semantics. void CheckOverrideControl(NamedDecl *D); /// DiagnoseAbsenceOfOverrideControl - Diagnose if 'override' keyword was /// not used in the declaration of an overriding method. void DiagnoseAbsenceOfOverrideControl(NamedDecl *D); /// CheckForFunctionMarkedFinal - Checks whether a virtual member function /// overrides a virtual member function marked 'final', according to /// C++11 [class.virtual]p4. bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old); //===--------------------------------------------------------------------===// // C++ Access Control // enum AccessResult { AR_accessible, AR_inaccessible, AR_dependent, AR_delayed }; bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS); AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, DeclAccessPair FoundDecl); AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, DeclAccessPair FoundDecl); AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, SourceRange PlacementRange, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, bool Diagnose = true); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, DeclAccessPair FoundDecl, const InitializedEntity &Entity, bool IsCopyBindingRefToTemp = false); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, DeclAccessPair FoundDecl, const InitializedEntity &Entity, const PartialDiagnostic &PDiag); AccessResult CheckDestructorAccess(SourceLocation Loc, CXXDestructorDecl *Dtor, const PartialDiagnostic &PDiag, QualType objectType = QualType()); AccessResult CheckFriendAccess(NamedDecl *D); AccessResult CheckMemberAccess(SourceLocation UseLoc, CXXRecordDecl *NamingClass, DeclAccessPair Found); AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, Expr *ArgExpr, DeclAccessPair FoundDecl); AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, unsigned DiagID, bool ForceCheck = false, bool ForceUnprivileged = false); void CheckLookupAccess(const LookupResult &R); bool IsSimplyAccessible(NamedDecl *decl, DeclContext *Ctx); bool isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, AccessSpecifier access, QualType objectType); void HandleDependentAccessCheck(const DependentDiagnostic &DD, const MultiLevelTemplateArgumentList &TemplateArgs); void PerformDependentDiagnostics(const DeclContext *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); void HandleDelayedAccessCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); /// \brief When true, access checking violations are treated as SFINAE /// failures rather than hard errors. bool AccessCheckingSFINAE; enum AbstractDiagSelID { AbstractNone = -1, AbstractReturnType, AbstractParamType, AbstractVariableType, AbstractFieldType, AbstractIvarType, AbstractSynthesizedIvarType, AbstractArrayType }; bool isAbstractType(SourceLocation Loc, QualType T); bool RequireNonAbstractType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); template bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireNonAbstractType(Loc, T, Diagnoser); } void DiagnoseAbstractType(const CXXRecordDecl *RD); //===--------------------------------------------------------------------===// // C++ Overloaded Operators [C++ 13.5] // bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // void FilterAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true); bool hasAnyAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true); void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool &MemberOfUnknownSpecialization); /// Determine whether a particular identifier might be the name in a C++1z /// deduction-guide declaration. bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name, SourceLocation NameLoc, ParsedTemplateTy *Template = nullptr); bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind); bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, NamedDecl *Instantiation, bool InstantiatedFromMember, const NamedDecl *Pattern, const NamedDecl *PatternDef, TemplateSpecializationKind TSK, bool Complain = true); void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); Decl *ActOnTypeParameter(Scope *S, bool Typename, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedType DefaultArg); QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, SourceLocation Loc); QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); Decl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position, SourceLocation EqualLoc, Expr *DefaultArg); Decl *ActOnTemplateTemplateParameter(Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params, SourceLocation EllipsisLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedTemplateArgument DefaultArg); TemplateParameterList * ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef Params, SourceLocation RAngleLoc, Expr *RequiresClause); /// \brief The context in which we are checking a template parameter list. enum TemplateParamListContext { TPC_ClassTemplate, TPC_VarTemplate, TPC_FunctionTemplate, TPC_ClassTemplateMember, TPC_FriendClassTemplate, TPC_FriendFunctionTemplate, TPC_FriendFunctionTemplateDefinition, TPC_TypeAliasTemplate }; bool CheckTemplateParameterList(TemplateParameterList *NewParams, TemplateParameterList *OldParams, TemplateParamListContext TPC); TemplateParameterList *MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef ParamLists, bool IsFriend, bool &IsMemberSpecialization, bool &Invalid); DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody = nullptr); TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType, SourceLocation Loc); void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); void NoteAllFoundTemplates(TemplateName Name); QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs); TypeResult ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy Template, IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, bool IsCtorOrDtorName = false, bool IsClassName = false); /// \brief Parsed an elaborated-type-specifier that refers to a template-id, /// such as \c class T::template apply. TypeResult ActOnTagTemplateIdType(TagUseKind TUK, TypeSpecifierType TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc); DeclResult ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, bool IsPartialSpecialization); DeclResult CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation TemplateNameLoc, const TemplateArgumentListInfo &TemplateArgs); ExprResult CheckVarTemplateId(const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, VarTemplateDecl *Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, bool RequiresADL, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); TemplateNameKind ActOnDependentTemplateName( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool AllowInjectedClassName = false); DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody = nullptr); bool CheckTemplatePartialSpecializationArgs(SourceLocation Loc, TemplateDecl *PrimaryTemplate, unsigned NumExplicitArgs, ArrayRef Args); void CheckTemplatePartialSpecialization( ClassTemplatePartialSpecializationDecl *Partial); void CheckTemplatePartialSpecialization( VarTemplatePartialSpecializationDecl *Partial); Decl *ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D); bool CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, TemplateSpecializationKind NewTSK, NamedDecl *PrevDecl, TemplateSpecializationKind PrevTSK, SourceLocation PrevPtOfInstantiation, bool &SuppressNew); bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo &ExplicitTemplateArgs, LookupResult &Previous); bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, AttributeList *Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, Declarator &D); TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, Decl *Param, SmallVectorImpl &Converted, bool &HasDefaultArg); /// \brief Specifies the context in which a particular template /// argument is being checked. enum CheckTemplateArgumentKind { /// \brief The template argument was specified in the code or was /// instantiated with some deduced template arguments. CTAK_Specified, /// \brief The template argument was deduced via template argument /// deduction. CTAK_Deduced, /// \brief The template argument was deduced from an array bound /// via template argument deduction. CTAK_DeducedFromArrayBound }; bool CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, unsigned ArgumentPackIndex, SmallVectorImpl &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); /// \brief Check that the given template arguments can be be provided to /// the given template, converting the arguments along the way. /// /// \param Template The template to which the template arguments are being /// provided. /// /// \param TemplateLoc The location of the template name in the source. /// /// \param TemplateArgs The list of template arguments. If the template is /// a template template parameter, this function may extend the set of /// template arguments to also include substituted, defaulted template /// arguments. /// /// \param PartialTemplateArgs True if the list of template arguments is /// intentionally partial, e.g., because we're checking just the initial /// set of template arguments. /// /// \param Converted Will receive the converted, canonicalized template /// arguments. /// /// \param UpdateArgsWithConversions If \c true, update \p TemplateArgs to /// contain the converted forms of the template arguments as written. /// Otherwise, \p TemplateArgs will not be modified. /// /// \returns true if an error occurred, false otherwise. bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl &Converted, bool UpdateArgsWithConversions = true); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, SmallVectorImpl &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, TemplateArgumentLoc &Arg, unsigned ArgumentPackIndex); ExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc); ExprResult BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc); /// \brief Enumeration describing how template parameter lists are compared /// for equality. enum TemplateParameterListEqualKind { /// \brief We are matching the template parameter lists of two templates /// that might be redeclarations. /// /// \code /// template struct X; /// template struct X; /// \endcode TPL_TemplateMatch, /// \brief We are matching the template parameter lists of two template /// template parameters as part of matching the template parameter lists /// of two templates that might be redeclarations. /// /// \code /// template class TT> struct X; /// template class Other> struct X; /// \endcode TPL_TemplateTemplateParmMatch, /// \brief We are matching the template parameter lists of a template /// template argument against the template parameter lists of a template /// template parameter. /// /// \code /// template class Metafun> struct X; /// template struct integer_c; /// X xic; /// \endcode TPL_TemplateTemplateArgumentMatch }; bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc = SourceLocation()); bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); /// \brief Called when the parser has parsed a C++ typename /// specifier, e.g., "typename T::type". /// /// \param S The scope in which this typename type occurs. /// \param TypenameLoc the location of the 'typename' keyword /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param II the identifier we're retrieving (e.g., 'type' in the example). /// \param IdLoc the location of the identifier. TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc); /// \brief Called when the parser has parsed a C++ typename /// specifier that ends in a template-id, e.g., /// "typename MetaFun::template apply". /// /// \param S The scope in which this typename type occurs. /// \param TypenameLoc the location of the 'typename' keyword /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param TemplateLoc the location of the 'template' keyword, if any. /// \param TemplateName The template name. /// \param TemplateII The identifier used to name the template. /// \param TemplateIILoc The location of the template name. /// \param LAngleLoc The location of the opening angle bracket ('<'). /// \param TemplateArgs The template arguments. /// \param RAngleLoc The location of the closing angle bracket ('>'). TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, TemplateTy TemplateName, IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc); QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, SourceLocation IILoc); TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, DeclarationName Name); bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); ExprResult RebuildExprInCurrentInstantiation(Expr *E); bool RebuildTemplateParamsInCurrentInstantiation( TemplateParameterList *Params); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgumentList &Args); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgument *Args, unsigned NumArgs); //===--------------------------------------------------------------------===// // C++ Variadic Templates (C++0x [temp.variadic]) //===--------------------------------------------------------------------===// /// Determine whether an unexpanded parameter pack might be permitted in this /// location. Useful for error recovery. bool isUnexpandedParameterPackPermitted(); /// \brief The context in which an unexpanded parameter pack is /// being diagnosed. /// /// Note that the values of this enumeration line up with the first /// argument to the \c err_unexpanded_parameter_pack diagnostic. enum UnexpandedParameterPackContext { /// \brief An arbitrary expression. UPPC_Expression = 0, /// \brief The base type of a class type. UPPC_BaseType, /// \brief The type of an arbitrary declaration. UPPC_DeclarationType, /// \brief The type of a data member. UPPC_DataMemberType, /// \brief The size of a bit-field. UPPC_BitFieldWidth, /// \brief The expression in a static assertion. UPPC_StaticAssertExpression, /// \brief The fixed underlying type of an enumeration. UPPC_FixedUnderlyingType, /// \brief The enumerator value. UPPC_EnumeratorValue, /// \brief A using declaration. UPPC_UsingDeclaration, /// \brief A friend declaration. UPPC_FriendDeclaration, /// \brief A declaration qualifier. UPPC_DeclarationQualifier, /// \brief An initializer. UPPC_Initializer, /// \brief A default argument. UPPC_DefaultArgument, /// \brief The type of a non-type template parameter. UPPC_NonTypeTemplateParameterType, /// \brief The type of an exception. UPPC_ExceptionType, /// \brief Partial specialization. UPPC_PartialSpecialization, /// \brief Microsoft __if_exists. UPPC_IfExists, /// \brief Microsoft __if_not_exists. UPPC_IfNotExists, /// \brief Lambda expression. UPPC_Lambda, /// \brief Block expression, UPPC_Block }; /// \brief Diagnose unexpanded parameter packs. /// /// \param Loc The location at which we should emit the diagnostic. /// /// \param UPPC The context in which we are diagnosing unexpanded /// parameter packs. /// /// \param Unexpanded the set of unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPacks(SourceLocation Loc, UnexpandedParameterPackContext UPPC, ArrayRef Unexpanded); /// \brief If the given type contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The source location where a diagnostc should be emitted. /// /// \param T The type that is being checked for unexpanded parameter /// packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, UnexpandedParameterPackContext UPPC); /// \brief If the given expression contains an unexpanded parameter /// pack, diagnose the error. /// /// \param E The expression that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(Expr *E, UnexpandedParameterPackContext UPPC = UPPC_Expression); /// \brief If the given nested-name-specifier contains an unexpanded /// parameter pack, diagnose the error. /// /// \param SS The nested-name-specifier that is being checked for /// unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, UnexpandedParameterPackContext UPPC); /// \brief If the given name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param NameInfo The name (with source location information) that /// is being checked for unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, UnexpandedParameterPackContext UPPC); /// \brief If the given template name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The location of the template name. /// /// \param Template The template name that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TemplateName Template, UnexpandedParameterPackContext UPPC); /// \brief If the given template argument contains an unexpanded parameter /// pack, diagnose the error. /// /// \param Arg The template argument that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, UnexpandedParameterPackContext UPPC); /// \brief Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgument Arg, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// type. /// /// \param T The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(QualType T, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// type. /// /// \param TL The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// nested-name-specifier. /// /// \param NNS The nested-name-specifier that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(NestedNameSpecifierLoc NNS, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// name. /// /// \param NameInfo The name that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, SmallVectorImpl &Unexpanded); /// \brief Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// /// \param Arg The template argument preceding the ellipsis, which /// may already be invalid. /// /// \param EllipsisLoc The location of the ellipsis. ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc); /// \brief Invoked when parsing a type followed by an ellipsis, which /// creates a pack expansion. /// /// \param Type The type preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); /// \brief Construct a pack expansion type from the pattern of the pack /// expansion. TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions); /// \brief Construct a pack expansion type from the pattern of the pack /// expansion. QualType CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, Optional NumExpansions); /// \brief Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); /// \brief Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions); /// \brief Determine whether we could expand a pack expansion with the /// given set of parameter packs into separate arguments by repeatedly /// transforming the pattern. /// /// \param EllipsisLoc The location of the ellipsis that identifies the /// pack expansion. /// /// \param PatternRange The source range that covers the entire pattern of /// the pack expansion. /// /// \param Unexpanded The set of unexpanded parameter packs within the /// pattern. /// /// \param ShouldExpand Will be set to \c true if the transformer should /// expand the corresponding pack expansions into separate arguments. When /// set, \c NumExpansions must also be set. /// /// \param RetainExpansion Whether the caller should add an unexpanded /// pack expansion after all of the expanded arguments. This is used /// when extending explicitly-specified template argument packs per /// C++0x [temp.arg.explicit]p9. /// /// \param NumExpansions The number of separate arguments that will be in /// the expanded form of the corresponding pack expansion. This is both an /// input and an output parameter, which can be set by the caller if the /// number of expansions is known a priori (e.g., due to a prior substitution) /// and will be set by the callee when the number of expansions is known. /// The callee must set this value when \c ShouldExpand is \c true; it may /// set this value in other cases. /// /// \returns true if an error occurred (e.g., because the parameter packs /// are to be instantiated with arguments of different lengths), false /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) /// must be set. bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, bool &RetainExpansion, Optional &NumExpansions); /// \brief Determine the number of arguments in the given pack expansion /// type. /// /// This routine assumes that the number of arguments in the expansion is /// consistent across all of the unexpanded parameter packs in its pattern. /// /// Returns an empty Optional if the type can't be expanded. Optional getNumArgumentsInExpansion(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs); /// \brief Determine whether the given declarator contains any unexpanded /// parameter packs. /// /// This routine is used by the parser to disambiguate function declarators /// with an ellipsis prior to the ')', e.g., /// /// \code /// void f(T...); /// \endcode /// /// To determine whether we have an (unnamed) function parameter pack or /// a variadic function. /// /// \returns true if the declarator contains any unexpanded parameter packs, /// false otherwise. bool containsUnexpandedParameterPacks(Declarator &D); /// \brief Returns the pattern of the pack expansion for a template argument. /// /// \param OrigLoc The template argument to expand. /// /// \param Ellipsis Will be set to the location of the ellipsis. /// /// \param NumExpansions Will be set to the number of expansions that will /// be generated from this pack expansion, if known a priori. TemplateArgumentLoc getTemplateArgumentPackExpansionPattern( TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis, Optional &NumExpansions) const; /// Given a template argument that contains an unexpanded parameter pack, but /// which has already been substituted, attempt to determine the number of /// elements that will be produced once this argument is fully-expanded. /// /// This is intended for use when transforming 'sizeof...(Arg)' in order to /// avoid actually expanding the pack where possible. Optional getFullyPackExpandedSize(TemplateArgument Arg); //===--------------------------------------------------------------------===// // C++ Template Argument Deduction (C++ [temp.deduct]) //===--------------------------------------------------------------------===// /// Adjust the type \p ArgFunctionType to match the calling convention, /// noreturn, and optionally the exception specification of \p FunctionType. /// Deduction often wants to ignore these properties when matching function /// types. QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType, bool AdjustExceptionSpec = false); /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of /// template argument deduction, as returned from /// DeduceTemplateArguments(). The separate TemplateDeductionInfo /// structure provides additional information about the results of /// template argument deduction, e.g., the deduced template argument /// list (if successful) or the specific template parameters or /// deduced arguments that were involved in the failure. enum TemplateDeductionResult { /// \brief Template argument deduction was successful. TDK_Success = 0, /// \brief The declaration was invalid; do nothing. TDK_Invalid, /// \brief Template argument deduction exceeded the maximum template /// instantiation depth (which has already been diagnosed). TDK_InstantiationDepth, /// \brief Template argument deduction did not deduce a value /// for every template parameter. TDK_Incomplete, /// \brief Template argument deduction produced inconsistent /// deduced values for the given template parameter. TDK_Inconsistent, /// \brief Template argument deduction failed due to inconsistent /// cv-qualifiers on a template parameter type that would /// otherwise be deduced, e.g., we tried to deduce T in "const T" /// but were given a non-const "X". TDK_Underqualified, /// \brief Substitution of the deduced template argument values /// resulted in an error. TDK_SubstitutionFailure, /// \brief After substituting deduced template arguments, a dependent /// parameter type did not match the corresponding argument. TDK_DeducedMismatch, /// \brief After substituting deduced template arguments, an element of /// a dependent parameter type did not match the corresponding element /// of the corresponding argument (when deducing from an initializer list). TDK_DeducedMismatchNested, /// \brief A non-depnedent component of the parameter did not match the /// corresponding component of the argument. TDK_NonDeducedMismatch, /// \brief When performing template argument deduction for a function /// template, there were too many call arguments. TDK_TooManyArguments, /// \brief When performing template argument deduction for a function /// template, there were too few call arguments. TDK_TooFewArguments, /// \brief The explicitly-specified template arguments were not valid /// template arguments for the given template. TDK_InvalidExplicitArguments, /// \brief Checking non-dependent argument conversions failed. TDK_NonDependentConversionFailure, /// \brief Deduction failed; that's all we know. TDK_MiscellaneousDeductionFailure, /// \brief CUDA Target attributes do not match. TDK_CUDATargetMismatch }; TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, sema::TemplateDeductionInfo &Info); TemplateDeductionResult SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo &ExplicitTemplateArgs, SmallVectorImpl &Deduced, SmallVectorImpl &ParamTypes, QualType *FunctionType, sema::TemplateDeductionInfo &Info); /// brief A function argument from which we performed template argument // deduction for a call. struct OriginalCallArg { OriginalCallArg(QualType OriginalParamType, bool DecomposedParam, unsigned ArgIdx, QualType OriginalArgType) : OriginalParamType(OriginalParamType), DecomposedParam(DecomposedParam), ArgIdx(ArgIdx), OriginalArgType(OriginalArgType) {} QualType OriginalParamType; bool DecomposedParam; unsigned ArgIdx; QualType OriginalArgType; }; TemplateDeductionResult FinishTemplateArgumentDeduction( FunctionTemplateDecl *FunctionTemplate, SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, SmallVectorImpl const *OriginalCallArgs = nullptr, bool PartialOverloading = false, llvm::function_ref CheckNonDependent = []{ return false; }); TemplateDeductionResult DeduceTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool PartialOverloading, llvm::function_ref)> CheckNonDependent); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool IsAddressOfFunction = false); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ToType, CXXConversionDecl *&Specialization, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool IsAddressOfFunction = false); /// \brief Substitute Replacement for \p auto in \p TypeWithAuto QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement); /// \brief Substitute Replacement for auto in TypeWithAuto TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); /// \brief Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. This does not retain any \c auto type sugar. QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement); /// \brief Result type of DeduceAutoType. enum DeduceAutoResult { DAR_Succeeded, DAR_Failed, DAR_FailedAlreadyDiagnosed }; DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result, Optional DependentDeductionDepth = None); DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result, Optional DependentDeductionDepth = None); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, bool Diagnose = true); /// \brief Declare implicit deduction guides for a class template if we've /// not already done so. void DeclareImplicitDeductionGuides(TemplateDecl *Template, SourceLocation Loc); QualType DeduceTemplateSpecializationFromInitializer( TypeSourceInfo *TInfo, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Init); QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, QualType Type, TypeSourceInfo *TSI, SourceRange Range, bool DirectInit, Expr *Init); TypeLoc getReturnTypeLoc(FunctionDecl *FD) const; bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, Expr *&RetExpr, AutoType *AT); FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplateSpecCandidateSet &FailedCandidates, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag, bool Complain = true, QualType TargetType = QualType()); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); bool isMoreSpecializedThanPrimary(ClassTemplatePartialSpecializationDecl *T, sema::TemplateDeductionInfo &Info); VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); bool isMoreSpecializedThanPrimary(VarTemplatePartialSpecializationDecl *T, sema::TemplateDeductionInfo &Info); bool isTemplateTemplateParameterAtLeastAsSpecializedAs( TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc); void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used); void MarkDeducedTemplateParameters( const FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced) { return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced); } static void MarkDeducedTemplateParameters(ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced); //===--------------------------------------------------------------------===// // C++ Template Instantiation // MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); /// A context in which code is being synthesized (where a source location /// alone is not sufficient to identify the context). This covers template /// instantiation and various forms of implicitly-generated functions. struct CodeSynthesisContext { /// \brief The kind of template instantiation we are performing enum SynthesisKind { /// We are instantiating a template declaration. The entity is /// the declaration we're instantiating (e.g., a CXXRecordDecl). TemplateInstantiation, /// We are instantiating a default argument for a template /// parameter. The Entity is the template parameter whose argument is /// being instantiated, the Template is the template, and the /// TemplateArgs/NumTemplateArguments provide the template arguments as /// specified. DefaultTemplateArgumentInstantiation, /// We are instantiating a default argument for a function. /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs /// provides the template arguments as specified. DefaultFunctionArgumentInstantiation, /// We are substituting explicit template arguments provided for /// a function template. The entity is a FunctionTemplateDecl. ExplicitTemplateArgumentSubstitution, /// We are substituting template argument determined as part of /// template argument deduction for either a class template /// partial specialization or a function template. The /// Entity is either a {Class|Var}TemplatePartialSpecializationDecl or /// a TemplateDecl. DeducedTemplateArgumentSubstitution, /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. PriorTemplateArgumentSubstitution, /// We are checking the validity of a default template argument that /// has been used when naming a template-id. DefaultTemplateArgumentChecking, /// We are instantiating the exception specification for a function /// template which was deferred until it was needed. ExceptionSpecInstantiation, /// We are declaring an implicit special member function. DeclaringSpecialMember, } Kind; /// \brief Was the enclosing context a non-instantiation SFINAE context? bool SavedInNonInstantiationSFINAEContext; /// \brief The point of instantiation or synthesis within the source code. SourceLocation PointOfInstantiation; /// \brief The entity that is being synthesized. Decl *Entity; /// \brief The template (or partial specialization) in which we are /// performing the instantiation, for substitutions of prior template /// arguments. NamedDecl *Template; /// \brief The list of template arguments we are substituting, if they /// are not part of the entity. const TemplateArgument *TemplateArgs; // FIXME: Wrap this union around more members, or perhaps store the // kind-specific members in the RAII object owning the context. union { /// \brief The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; /// \brief The special member being declared or defined. CXXSpecialMember SpecialMember; }; ArrayRef template_arguments() const { assert(Kind != DeclaringSpecialMember); return {TemplateArgs, NumTemplateArgs}; } /// \brief The template deduction info object associated with the /// substitution or checking of explicit or deduced template arguments. sema::TemplateDeductionInfo *DeductionInfo; /// \brief The source range that covers the construct that cause /// the instantiation, e.g., the template-id that causes a class /// template instantiation. SourceRange InstantiationRange; CodeSynthesisContext() : Kind(TemplateInstantiation), Entity(nullptr), Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {} /// \brief Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. bool isInstantiationRecord() const; }; /// \brief List of active code synthesis contexts. /// /// This vector is treated as a stack. As synthesis of one entity requires /// synthesis of another, additional contexts are pushed onto the stack. SmallVector CodeSynthesisContexts; /// Specializations whose definitions are currently being instantiated. llvm::DenseSet> InstantiatingSpecializations; /// Non-dependent types used in templates that have already been instantiated /// by some template instantiation. llvm::DenseSet InstantiatedNonDependentTypes; /// \brief Extra modules inspected when performing a lookup during a template /// instantiation. Computed lazily. SmallVector CodeSynthesisContextLookupModules; /// \brief Cache of additional modules that should be used for name lookup /// within the current template instantiation. Computed lazily; use /// getLookupModules() to get a complete set. llvm::DenseSet LookupModulesCache; /// \brief Get the set of additional modules that should be checked during /// name lookup. A module and its imports become visible when instanting a /// template defined within it. llvm::DenseSet &getLookupModules(); /// \brief Map from the most recent declaration of a namespace to the most /// recent visible declaration of that namespace. llvm::DenseMap VisibleNamespaceCache; /// \brief Whether we are in a SFINAE context that is not associated with /// template instantiation. /// /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside /// of a template instantiation or template argument deduction. bool InNonInstantiationSFINAEContext; /// \brief The number of \p CodeSynthesisContexts that are not template /// instantiations and, therefore, should not be counted as part of the /// instantiation depth. /// /// When the instantiation depth reaches the user-configurable limit /// \p LangOptions::InstantiationDepth we will abort instantiation. // FIXME: Should we have a similar limit for other forms of synthesis? unsigned NonInstantiationEntries; /// \brief The depth of the context stack at the point when the most recent /// error or warning was produced. /// /// This value is used to suppress printing of redundant context stacks /// when there are multiple errors or warnings in the same instantiation. // FIXME: Does this belong in Sema? It's tough to implement it anywhere else. unsigned LastEmittedCodeSynthesisContextDepth = 0; /// \brief The current index into pack expansion arguments that will be /// used for substitution of parameter packs. /// /// The pack expansion index will be -1 to indicate that parameter packs /// should be instantiated as themselves. Otherwise, the index specifies /// which argument within the parameter pack will be used for substitution. int ArgumentPackSubstitutionIndex; /// \brief RAII object used to change the argument pack substitution index /// within a \c Sema object. /// /// See \c ArgumentPackSubstitutionIndex for more information. class ArgumentPackSubstitutionIndexRAII { Sema &Self; int OldSubstitutionIndex; public: ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; } ~ArgumentPackSubstitutionIndexRAII() { Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; } }; friend class ArgumentPackSubstitutionRAII; /// \brief For each declaration that involved template argument deduction, the /// set of diagnostics that were suppressed during that template argument /// deduction. /// /// FIXME: Serialize this structure to the AST file. typedef llvm::DenseMap > SuppressedDiagnosticsMap; SuppressedDiagnosticsMap SuppressedDiagnostics; /// \brief A stack object to be created when performing template /// instantiation. /// /// Construction of an object of type \c InstantiatingTemplate /// pushes the current instantiation onto the stack of active /// instantiations. If the size of this stack exceeds the maximum /// number of recursive template instantiations, construction /// produces an error and evaluates true. /// /// Destruction of this object will pop the named instantiation off /// the stack. struct InstantiatingTemplate { /// \brief Note that we are instantiating a class template, /// function template, variable template, alias template, /// or a member thereof. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange = SourceRange()); struct ExceptionSpecification {}; /// \brief Note that we are instantiating an exception specification /// of a function template. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity, ExceptionSpecification, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating a default argument in a /// template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateParameter Param, TemplateDecl *Template, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are substituting either explicitly-specified or /// deduced template arguments during function template argument deduction. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, ArrayRef TemplateArgs, CodeSynthesisContext::SynthesisKind Kind, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating as part of template /// argument deduction for a class template declaration. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating as part of template /// argument deduction for a class template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating as part of template /// argument deduction for a variable template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, VarTemplatePartialSpecializationDecl *PartialSpec, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating a default argument for a function /// parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are substituting prior template arguments into a /// non-type parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, NonTypeTemplateParmDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// \brief Note that we are substituting prior template arguments into a /// template template parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, TemplateTemplateParmDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// \brief Note that we are checking the default template argument /// against the template parameter for a given template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, NamedDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// \brief Note that we have finished instantiating this template. void Clear(); ~InstantiatingTemplate() { Clear(); } /// \brief Determines whether we have exceeded the maximum /// recursive template instantiations. bool isInvalid() const { return Invalid; } /// \brief Determine whether we are already instantiating this /// specialization in some surrounding active instantiation. bool isAlreadyInstantiating() const { return AlreadyInstantiating; } private: Sema &SemaRef; bool Invalid; bool AlreadyInstantiating; bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); InstantiatingTemplate( Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind, SourceLocation PointOfInstantiation, SourceRange InstantiationRange, Decl *Entity, NamedDecl *Template = nullptr, ArrayRef TemplateArgs = None, sema::TemplateDeductionInfo *DeductionInfo = nullptr); InstantiatingTemplate(const InstantiatingTemplate&) = delete; InstantiatingTemplate& operator=(const InstantiatingTemplate&) = delete; }; void pushCodeSynthesisContext(CodeSynthesisContext Ctx); void popCodeSynthesisContext(); /// Determine whether we are currently performing template instantiation. bool inTemplateInstantiation() const { return CodeSynthesisContexts.size() > NonInstantiationEntries; } void PrintContextStack() { if (!CodeSynthesisContexts.empty() && CodeSynthesisContexts.size() != LastEmittedCodeSynthesisContextDepth) { PrintInstantiationStack(); LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size(); } if (PragmaAttributeCurrentTargetDecl) PrintPragmaAttributeInstantiationPoint(); } void PrintInstantiationStack(); void PrintPragmaAttributeInstantiationPoint(); /// \brief Determines whether we are currently in a context where /// template argument substitution failures are not considered /// errors. /// /// \returns An empty \c Optional if we're not in a SFINAE context. /// Otherwise, contains a pointer that, if non-NULL, contains the nearest /// template-deduction context object, which can be used to capture /// diagnostics that will be suppressed. Optional isSFINAEContext() const; /// \brief Determines whether we are currently in a context that /// is not evaluated as per C++ [expr] p5. bool isUnevaluatedContext() const { assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); return ExprEvalContexts.back().isUnevaluated(); } /// \brief RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument /// deduction. class SFINAETrap { Sema &SemaRef; unsigned PrevSFINAEErrors; bool PrevInNonInstantiationSFINAEContext; bool PrevAccessCheckingSFINAE; public: explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), PrevInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext), PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) { if (!SemaRef.isSFINAEContext()) SemaRef.InNonInstantiationSFINAEContext = true; SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; } ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; SemaRef.InNonInstantiationSFINAEContext = PrevInNonInstantiationSFINAEContext; SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; } /// \brief Determine whether any SFINAE errors have been trapped. bool hasErrorOccurred() const { return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; } }; /// \brief RAII class used to indicate that we are performing provisional /// semantic analysis to determine the validity of a construct, so /// typo-correction and diagnostics in the immediate context (not within /// implicitly-instantiated templates) should be suppressed. class TentativeAnalysisScope { Sema &SemaRef; // FIXME: Using a SFINAETrap for this is a hack. SFINAETrap Trap; bool PrevDisableTypoCorrection; public: explicit TentativeAnalysisScope(Sema &SemaRef) : SemaRef(SemaRef), Trap(SemaRef, true), PrevDisableTypoCorrection(SemaRef.DisableTypoCorrection) { SemaRef.DisableTypoCorrection = true; } ~TentativeAnalysisScope() { SemaRef.DisableTypoCorrection = PrevDisableTypoCorrection; } }; /// \brief The current instantiation scope used to store local /// variables. LocalInstantiationScope *CurrentInstantiationScope; /// \brief Tracks whether we are in a context where typo correction is /// disabled. bool DisableTypoCorrection; /// \brief The number of typos corrected by CorrectTypo. unsigned TyposCorrected; typedef llvm::SmallSet SrcLocSet; typedef llvm::DenseMap IdentifierSourceLocations; /// \brief A cache containing identifiers for which typo correction failed and /// their locations, so that repeated attempts to correct an identifier in a /// given location are ignored if typo correction already failed for it. IdentifierSourceLocations TypoCorrectionFailures; /// \brief Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; threadSafety::BeforeSet *ThreadSafetyDeclCache; /// \brief An entity for which implicit template instantiation is required. /// /// The source location associated with the declaration is the first place in /// the source code where the declaration was "used". It is not necessarily /// the point of instantiation (which will be either before or after the /// namespace-scope declaration that triggered this implicit instantiation), /// However, it is the location that diagnostics should generally refer to, /// because users will need to know what code triggered the instantiation. typedef std::pair PendingImplicitInstantiation; /// \brief The queue of implicit template instantiations that are required /// but have not yet been performed. std::deque PendingInstantiations; class SavePendingInstantiationsAndVTableUsesRAII { public: SavePendingInstantiationsAndVTableUsesRAII(Sema &S, bool Enabled) : S(S), Enabled(Enabled) { if (!Enabled) return; SavedPendingInstantiations.swap(S.PendingInstantiations); SavedVTableUses.swap(S.VTableUses); } ~SavePendingInstantiationsAndVTableUsesRAII() { if (!Enabled) return; // Restore the set of pending vtables. assert(S.VTableUses.empty() && "VTableUses should be empty before it is discarded."); S.VTableUses.swap(SavedVTableUses); // Restore the set of pending implicit instantiations. assert(S.PendingInstantiations.empty() && "PendingInstantiations should be empty before it is discarded."); S.PendingInstantiations.swap(SavedPendingInstantiations); } private: Sema &S; SmallVector SavedVTableUses; std::deque SavedPendingInstantiations; bool Enabled; }; /// \brief The queue of implicit template instantiations that are required /// and must be performed within the current local scope. /// /// This queue is only used for member functions of local classes in /// templates, which must be instantiated in the same scope as their /// enclosing function, so that they can reference function-local /// types, static variables, enumerators, etc. std::deque PendingLocalImplicitInstantiations; class SavePendingLocalImplicitInstantiationsRAII { public: SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) { SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } ~SavePendingLocalImplicitInstantiationsRAII() { assert(S.PendingLocalImplicitInstantiations.empty() && "there shouldn't be any pending local implicit instantiations"); SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } private: Sema &S; std::deque SavedPendingLocalImplicitInstantiations; }; /// A helper class for building up ExtParameterInfos. class ExtParameterInfoBuilder { SmallVector Infos; bool HasInteresting = false; public: /// Set the ExtParameterInfo for the parameter at the given index, /// void set(unsigned index, FunctionProtoType::ExtParameterInfo info) { assert(Infos.size() <= index); Infos.resize(index); Infos.push_back(info); if (!HasInteresting) HasInteresting = (info != FunctionProtoType::ExtParameterInfo()); } /// Return a pointer (suitable for setting in an ExtProtoInfo) to the /// ExtParameterInfo array we've built up. const FunctionProtoType::ExtParameterInfo * getPointerOrNull(unsigned numParams) { if (!HasInteresting) return nullptr; Infos.resize(numParams); return Infos.data(); } }; void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity, bool AllowDeducedTST = false); QualType SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); TypeSourceInfo *SubstType(TypeLoc TL, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, unsigned ThisTypeQuals); void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, const MultiLevelTemplateArgumentList &Args); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, Optional NumExpansions, bool ExpectParameterPack); bool SubstParmTypes(SourceLocation Loc, ArrayRef Params, const FunctionProtoType::ExtParameterInfo *ExtParamInfos, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &ParamTypes, SmallVectorImpl *OutParams, ExtParameterInfoBuilder &ParamInfos); ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); /// \brief Substitute the given template arguments into a list of /// expressions, expanding pack expansions if required. /// /// \param Exprs The list of expressions to substitute into. /// /// \param IsCall Whether this is some form of call, in which case /// default arguments will be dropped. /// /// \param TemplateArgs The set of template arguments to substitute. /// /// \param Outputs Will receive all of the substituted arguments. /// /// \returns true if an error occurred, false otherwise. bool SubstExprs(ArrayRef Exprs, bool IsCall, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &Outputs); StmtResult SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs); Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); ExprResult SubstInitializer(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit); bool SubstBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); bool InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK, bool Complain = true); bool InstantiateEnum(SourceLocation PointOfInstantiation, EnumDecl *Instantiation, EnumDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK); bool InstantiateInClassInitializer( SourceLocation PointOfInstantiation, FieldDecl *Instantiation, FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); struct LateInstantiatedAttribute { const Attr *TmplAttr; LocalInstantiationScope *Scope; Decl *NewDecl; LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S, Decl *D) : TmplAttr(A), Scope(S), NewDecl(D) { } }; typedef SmallVector LateInstantiatedAttrVec; void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Pattern, Decl *Inst, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); void InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Pattern, Decl *Inst, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); bool InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool Complain = true); void InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK); void InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK); NestedNameSpecifierLoc SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, const MultiLevelTemplateArgumentList &TemplateArgs); DeclarationNameInfo SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, const MultiLevelTemplateArgumentList &TemplateArgs); TemplateName SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs); bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, TemplateArgumentListInfo &Result, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, FunctionDecl *Function); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); VarTemplateSpecializationDecl *BuildVarTemplateInstantiation( VarTemplateDecl *VarTemplate, VarDecl *FromVar, const TemplateArgumentList &TemplateArgList, const TemplateArgumentListInfo &TemplateArgsInfo, SmallVectorImpl &Converted, SourceLocation PointOfInstantiation, void *InsertPos, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *StartingScope = nullptr); VarTemplateSpecializationDecl *CompleteVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, const MultiLevelTemplateArgumentList &TemplateArgs); void BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs, LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner, LocalInstantiationScope *StartingScope, bool InstantiatingVarTemplate = false); void InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); void InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive = false, bool DefinitionRequired = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs); NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs); DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); // Objective-C declarations. enum ObjCContainerKind { OCK_None = -1, OCK_Interface = 0, OCK_Protocol, OCK_Category, OCK_ClassExtension, OCK_Implementation, OCK_CategoryImplementation }; ObjCContainerKind getObjCContainerKind() const; DeclResult actOnObjCTypeParam(Scope *S, ObjCTypeParamVariance variance, SourceLocation varianceLoc, unsigned index, IdentifierInfo *paramName, SourceLocation paramLoc, SourceLocation colonLoc, ParsedType typeBound); ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc, ArrayRef typeParams, SourceLocation rAngleLoc); void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); Decl *ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, ArrayRef SuperTypeArgs, SourceRange SuperTypeArgsRange, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); void ActOnSuperClassOfClassInterface(Scope *S, SourceLocation AtInterfaceLoc, ObjCInterfaceDecl *IDecl, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, ArrayRef SuperTypeArgs, SourceRange SuperTypeArgsRange); void ActOnTypedefedProtocols(SmallVectorImpl &ProtocolRefs, SmallVectorImpl &ProtocolLocs, IdentifierInfo *SuperName, SourceLocation SuperLoc); Decl *ActOnCompatibilityAlias( SourceLocation AtCompatibilityAliasLoc, IdentifierInfo *AliasName, SourceLocation AliasLocation, IdentifierInfo *ClassName, SourceLocation ClassLocation); bool CheckForwardProtocolDeclarationForCircularDependency( IdentifierInfo *PName, SourceLocation &PLoc, SourceLocation PrevLoc, const ObjCList &PList); Decl *ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, Decl * const *ProtoRefNames, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); Decl *ActOnStartClassImplementation( SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc); Decl *ActOnStartCategoryImplementation(SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc); DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef Decls); DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, ArrayRef TypeParamLists, unsigned NumElts); DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, ArrayRef IdentList, AttributeList *attrList); void FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, ArrayRef ProtocolId, SmallVectorImpl &Protocols); void DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, SourceLocation ProtocolLoc, IdentifierInfo *TypeArgId, SourceLocation TypeArgLoc, bool SelectProtocolFirst = false); /// Given a list of identifiers (and their locations), resolve the /// names to either Objective-C protocol qualifiers or type /// arguments, as appropriate. void actOnObjCTypeArgsOrProtocolQualifiers( Scope *S, ParsedType baseType, SourceLocation lAngleLoc, ArrayRef identifiers, ArrayRef identifierLocs, SourceLocation rAngleLoc, SourceLocation &typeArgsLAngleLoc, SmallVectorImpl &typeArgs, SourceLocation &typeArgsRAngleLoc, SourceLocation &protocolLAngleLoc, SmallVectorImpl &protocols, SourceLocation &protocolRAngleLoc, bool warnOnIncompleteProtocols); /// Build a an Objective-C protocol-qualified 'id' type where no /// base type was specified. TypeResult actOnObjCProtocolQualifierType( SourceLocation lAngleLoc, ArrayRef protocols, ArrayRef protocolLocs, SourceLocation rAngleLoc); /// Build a specialized and/or protocol-qualified Objective-C type. TypeResult actOnObjCTypeArgsAndProtocolQualifiers( Scope *S, SourceLocation Loc, ParsedType BaseType, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc); /// Build an Objective-C type parameter type. QualType BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, bool FailOnError = false); /// Build an Objective-C object pointer type. QualType BuildObjCObjectType(QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, bool FailOnError = false); /// Check the application of the Objective-C '__kindof' qualifier to /// the given type. bool checkObjCKindOfType(QualType &type, SourceLocation loc); /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \p PropertyTy. void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, SourceLocation Loc, unsigned &Attributes, bool propertyInPrimaryClass); /// Process the specified property declaration and create decls for the /// setters and getters as needed. /// \param property The property declaration being processed void ProcessPropertyDecl(ObjCPropertyDecl *property); void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *Name, bool OverridingProtocolProperty); void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods = None, ArrayRef allTUVars = None); Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); Decl *ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar, SourceLocation PropertyIvarLoc, ObjCPropertyQueryKind QueryKind); enum ObjCSpecialMethodKind { OSMK_None, OSMK_Alloc, OSMK_New, OSMK_Copy, OSMK_RetainingInit, OSMK_NonRetainingInit }; struct ObjCArgInfo { IdentifierInfo *Name; SourceLocation NameLoc; // The Type is null if no type was specified, and the DeclSpec is invalid // in this case. ParsedType Type; ObjCDeclSpec DeclSpec; /// ArgAttrs - Attribute list for this argument. AttributeList *ArgAttrs; }; Decl *ActOnMethodDeclaration( Scope *S, SourceLocation BeginLoc, // location of the + or -. SourceLocation EndLoc, // location of the ; or {. tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, ArrayRef SelectorLocs, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, bool isVariadic, bool MethodDefinition); ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, const ObjCObjectPointerType *OPT, bool IsInstance); ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, bool IsInstance); bool CheckARCMethodDecl(ObjCMethodDecl *method); bool inferObjCARCLifetime(ValueDecl *decl); ExprResult HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, SourceLocation OpLoc, DeclarationName MemberName, SourceLocation MemberLoc, SourceLocation SuperLoc, QualType SuperType, bool Super); ExprResult ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo &propertyName, SourceLocation receiverNameLoc, SourceLocation propertyNameLoc); ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc); /// \brief Describes the kind of message expression indicated by a message /// send that starts with an identifier. enum ObjCMessageKind { /// \brief The message is sent to 'super'. ObjCSuperMessage, /// \brief The message is an instance message. ObjCInstanceMessage, /// \brief The message is a class message, and the identifier is a type /// name. ObjCClassMessage }; ObjCMessageKind getObjCMessageKind(Scope *S, IdentifierInfo *Name, SourceLocation NameLoc, bool IsSuper, bool HasTrailingDot, ParsedType &ReceiverType); ExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args, bool isImplicit = false); ExprResult BuildClassMessageImplicit(QualType ReceiverType, bool isSuperReceiver, SourceLocation Loc, Selector Sel, ObjCMethodDecl *Method, MultiExprArg Args); ExprResult ActOnClassMessage(Scope *S, ParsedType Receiver, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildInstanceMessage(Expr *Receiver, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args, bool isImplicit = false); ExprResult BuildInstanceMessageImplicit(Expr *Receiver, QualType ReceiverType, SourceLocation Loc, Selector Sel, ObjCMethodDecl *Method, MultiExprArg Args); ExprResult ActOnInstanceMessage(Scope *S, Expr *Receiver, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, Expr *SubExpr); ExprResult ActOnObjCBridgedCast(Scope *S, SourceLocation LParenLoc, ObjCBridgeCastKind Kind, SourceLocation BridgeKeywordLoc, ParsedType Type, SourceLocation RParenLoc, Expr *SubExpr); void CheckTollFreeBridgeCast(QualType castType, Expr *castExpr); void CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr); bool CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, CastKind &Kind); bool checkObjCBridgeRelatedComponents(SourceLocation Loc, QualType DestType, QualType SrcType, ObjCInterfaceDecl *&RelatedClass, ObjCMethodDecl *&ClassMethod, ObjCMethodDecl *&InstanceMethod, TypedefNameDecl *&TDNDecl, bool CfToNs, bool Diagnose = true); bool CheckObjCBridgeRelatedConversions(SourceLocation Loc, QualType DestType, QualType SrcType, Expr *&SrcExpr, bool Diagnose = true); bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr, bool Diagnose = true); bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); /// \brief Check whether the given new method is a valid override of the /// given overridden method, and set any properties that should be inherited. void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden); /// \brief Describes the compatibility of a result type with its method. enum ResultTypeCompatibilityKind { RTC_Compatible, RTC_Incompatible, RTC_Unknown }; void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, ObjCInterfaceDecl *CurrentClass, ResultTypeCompatibilityKind RTC); enum PragmaOptionsAlignKind { POAK_Native, // #pragma options align=native POAK_Natural, // #pragma options align=natural POAK_Packed, // #pragma options align=packed POAK_Power, // #pragma options align=power POAK_Mac68k, // #pragma options align=mac68k POAK_Reset // #pragma options align=reset }; /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc); /// ActOnPragmaPack - Called on well formed \#pragma pack(...). void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *Alignment); /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. void ActOnPragmaMSStruct(PragmaMSStructKind Kind); /// ActOnPragmaMSComment - Called on well formed /// \#pragma comment(kind, "arg"). void ActOnPragmaMSComment(SourceLocation CommentLoc, PragmaMSCommentKind Kind, StringRef Arg); /// ActOnPragmaMSPointersToMembers - called on well formed \#pragma /// pointers_to_members(representation method[, general purpose /// representation]). void ActOnPragmaMSPointersToMembers( LangOptions::PragmaMSPointersToMembersKind Kind, SourceLocation PragmaLoc); /// \brief Called on well formed \#pragma vtordisp(). void ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, SourceLocation PragmaLoc, MSVtorDispAttr::Mode Value); enum PragmaSectionKind { PSK_DataSeg, PSK_BSSSeg, PSK_ConstSeg, PSK_CodeSeg, }; bool UnifySection(StringRef SectionName, int SectionFlags, DeclaratorDecl *TheDecl); bool UnifySection(StringRef SectionName, int SectionFlags, SourceLocation PragmaSectionLocation); /// \brief Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. void ActOnPragmaMSSeg(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, StringLiteral *SegmentName, llvm::StringRef PragmaName); /// \brief Called on well formed \#pragma section(). void ActOnPragmaMSSection(SourceLocation PragmaLocation, int SectionFlags, StringLiteral *SegmentName); /// \brief Called on well-formed \#pragma init_seg(). void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, StringLiteral *SegmentName); /// \brief Called on #pragma clang __debug dump II void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, StringRef Value); /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'. void ActOnPragmaUnused(const Token &Identifier, Scope *curScope, SourceLocation PragmaLoc); /// ActOnPragmaVisibility - Called on well formed \#pragma GCC visibility... . void ActOnPragmaVisibility(const IdentifierInfo* VisType, SourceLocation PragmaLoc); NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, SourceLocation Loc); void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W); /// ActOnPragmaWeakID - Called on well formed \#pragma weak ident. void ActOnPragmaWeakID(IdentifierInfo* WeakName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc); /// ActOnPragmaRedefineExtname - Called on well formed /// \#pragma redefine_extname oldname newname. void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); /// ActOnPragmaWeakAlias - Called on well formed \#pragma weak ident = ident. void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); /// ActOnPragmaFPContract - Called on well formed /// \#pragma {STDC,OPENCL} FP_CONTRACT and /// \#pragma clang fp contract void ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC); /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. void AddAlignmentAttributesForRecord(RecordDecl *RD); /// AddMsStructLayoutForRecord - Adds ms_struct layout attribute to record. void AddMsStructLayoutForRecord(RecordDecl *RD); /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); /// PushNamespaceVisibilityAttr - Note that we've entered a /// namespace with a visibility attribute. void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, SourceLocation Loc); /// AddPushedVisibilityAttribute - If '\#pragma GCC visibility' was used, /// add an appropriate visibility attribute. void AddPushedVisibilityAttribute(Decl *RD); /// PopPragmaVisibility - Pop the top element of the visibility stack; used /// for '\#pragma GCC visibility' and visibility attributes on namespaces. void PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc); /// FreeVisContext - Deallocate and null out VisContext. void FreeVisContext(); /// AddCFAuditedAttribute - Check whether we're currently within /// '\#pragma clang arc_cf_code_audited' and, if so, consider adding /// the appropriate attribute. void AddCFAuditedAttribute(Decl *D); /// \brief Called on well-formed '\#pragma clang attribute push'. void ActOnPragmaAttributePush(AttributeList &Attribute, SourceLocation PragmaLoc, attr::ParsedSubjectMatchRuleSet Rules); /// \brief Called on well-formed '\#pragma clang attribute pop'. void ActOnPragmaAttributePop(SourceLocation PragmaLoc); /// \brief Adds the attributes that have been specified using the /// '\#pragma clang attribute push' directives to the given declaration. void AddPragmaAttributes(Scope *S, Decl *D); void DiagnoseUnterminatedPragmaAttribute(); /// \brief Called on well formed \#pragma clang optimize. void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); /// \brief Get the location for the currently active "\#pragma clang optimize /// off". If this location is invalid, then the state of the pragma is "on". SourceLocation getOptimizeOffPragmaLocation() const { return OptimizeOffPragmaLocation; } /// \brief Only called on function definitions; if there is a pragma in scope /// with the effect of a range-based optnone, consider marking the function /// with attribute optnone. void AddRangeBasedOptnone(FunctionDecl *FD); /// \brief Adds the 'optnone' attribute to the function declaration if there /// are no conflicts; Loc represents the location causing the 'optnone' /// attribute to be added (usually because of a pragma). void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc); /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, unsigned SpellingListIndex, bool IsPackExpansion); void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T, unsigned SpellingListIndex, bool IsPackExpansion); /// AddAssumeAlignedAttr - Adds an assume_aligned attribute to a particular /// declaration. void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE, unsigned SpellingListIndex); /// AddAllocAlignAttr - Adds an alloc_align attribute to a particular /// declaration. void AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, unsigned SpellingListIndex); /// AddAlignValueAttr - Adds an align_value attribute to a particular /// declaration. void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, unsigned SpellingListIndex); /// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular /// declaration. void AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, Expr *MinBlocks, unsigned SpellingListIndex); /// AddModeAttr - Adds a mode attribute to a particular declaration. void AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, unsigned SpellingListIndex, bool InInstantiation = false); void AddParameterABIAttr(SourceRange AttrRange, Decl *D, ParameterABI ABI, unsigned SpellingListIndex); void AddNSConsumedAttr(SourceRange AttrRange, Decl *D, unsigned SpellingListIndex, bool isNSConsumed, bool isTemplateInstantiation); //===--------------------------------------------------------------------===// // C++ Coroutines TS // ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult BuildResolvedCoawaitExpr(SourceLocation KwLoc, Expr *E, bool IsImplicit = false); ExprResult BuildUnresolvedCoawaitExpr(SourceLocation KwLoc, Expr *E, UnresolvedLookupExpr* Lookup); ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E); StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E, bool IsImplicit = false); StmtResult BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs); VarDecl *buildCoroutinePromise(SourceLocation Loc); void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body); //===--------------------------------------------------------------------===// // OpenCL extensions. // private: std::string CurrOpenCLExtension; /// Extensions required by an OpenCL type. llvm::DenseMap> OpenCLTypeExtMap; /// Extensions required by an OpenCL declaration. llvm::DenseMap> OpenCLDeclExtMap; public: llvm::StringRef getCurrentOpenCLExtension() const { return CurrOpenCLExtension; } void setCurrentOpenCLExtension(llvm::StringRef Ext) { CurrOpenCLExtension = Ext; } /// \brief Set OpenCL extensions for a type which can only be used when these /// OpenCL extensions are enabled. If \p Exts is empty, do nothing. /// \param Exts A space separated list of OpenCL extensions. void setOpenCLExtensionForType(QualType T, llvm::StringRef Exts); /// \brief Set OpenCL extensions for a declaration which can only be /// used when these OpenCL extensions are enabled. If \p Exts is empty, do /// nothing. /// \param Exts A space separated list of OpenCL extensions. void setOpenCLExtensionForDecl(Decl *FD, llvm::StringRef Exts); /// \brief Set current OpenCL extensions for a type which can only be used /// when these OpenCL extensions are enabled. If current OpenCL extension is /// empty, do nothing. void setCurrentOpenCLExtensionForType(QualType T); /// \brief Set current OpenCL extensions for a declaration which /// can only be used when these OpenCL extensions are enabled. If current /// OpenCL extension is empty, do nothing. void setCurrentOpenCLExtensionForDecl(Decl *FD); bool isOpenCLDisabledDecl(Decl *FD); /// \brief Check if type \p T corresponding to declaration specifier \p DS /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. bool checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType T); /// \brief Check if declaration \p D used by expression \p E /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. bool checkOpenCLDisabledDecl(const Decl &D, const Expr &E); //===--------------------------------------------------------------------===// // OpenMP directives and clauses. // private: void *VarDataSharingAttributesStack; /// Set to true inside '#pragma omp declare target' region. bool IsInOpenMPDeclareTargetContext = false; /// \brief Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind, bool StrictlyPositive = true); /// Returns OpenMP nesting level for current directive. unsigned getOpenMPNestingLevel() const; /// Push new OpenMP function region for non-capturing function. void pushOpenMPFunctionRegion(); /// Pop OpenMP function region for non-capturing function. void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI); /// Checks if a type or a declaration is disabled due to the owning extension /// being disabled, and emits diagnostic messages if it is disabled. /// \param D type or declaration to be checked. /// \param DiagLoc source location for the diagnostic message. /// \param DiagInfo information to be emitted for the diagnostic message. /// \param SrcRange source range of the declaration. /// \param Map maps type or declaration to the extensions. /// \param Selector selects diagnostic message: 0 for type and 1 for /// declaration. /// \return true if the type or declaration is disabled. template bool checkOpenCLDisabledTypeOrDecl(T D, DiagLocT DiagLoc, DiagInfoT DiagInfo, MapT &Map, unsigned Selector = 0, SourceRange SrcRange = SourceRange()); public: /// \brief Return true if the provided declaration \a VD should be captured by /// reference. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level); /// \brief Check if the specified variable is used in one of the private /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP /// constructs. VarDecl *IsOpenMPCapturedDecl(ValueDecl *D); ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, ExprObjectKind OK, SourceLocation Loc); /// \brief Check if the specified variable is used in 'private' clause. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool isOpenMPPrivateDecl(ValueDecl *D, unsigned Level); /// \brief Check if the specified variable is captured by 'target' directive. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level); ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); /// \brief Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc); /// \brief Start analysis of clauses. void StartOpenMPClause(OpenMPClauseKind K); /// \brief End analysis of clauses. void EndOpenMPClause(); /// \brief Called on end of data sharing attribute block. void EndOpenMPDSABlock(Stmt *CurDirective); /// \brief Check if the current region is an OpenMP loop region and if it is, /// mark loop control variable, used in \p Init for loop initialization, as /// private by default. /// \param Init First part of the for loop. void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init); // OpenMP directives and clauses. /// \brief Called on correct id-expression from the '#pragma omp /// threadprivate'. ExprResult ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id); /// \brief Called on well-formed '#pragma omp threadprivate'. DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( SourceLocation Loc, ArrayRef VarList); /// \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness. OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl( SourceLocation Loc, ArrayRef VarList); /// \brief Check if the specified type is allowed to be used in 'omp declare /// reduction' construct. QualType ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, TypeResult ParsedType); /// \brief Called on start of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveStart( Scope *S, DeclContext *DC, DeclarationName Name, ArrayRef> ReductionTypes, AccessSpecifier AS, Decl *PrevDeclInScope = nullptr); /// \brief Initialize declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D); /// \brief Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner); /// \brief Initialize declare reduction construct initializer. void ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); /// \brief Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer); /// \brief Called at the end of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); /// Called on the start of target region i.e. '#pragma omp declare target'. bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc); /// Called at the end of target region i.e. '#pragme omp end declare target'. void ActOnFinishOpenMPDeclareTargetDirective(); /// Called on correct id-expression from the '#pragma omp declare target'. void ActOnOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id, OMPDeclareTargetDeclAttr::MapTypeTy MT, NamedDeclSetType &SameDirectiveDecls); /// Check declaration inside target region. void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D); /// Return true inside OpenMP target region. bool isInOpenMPDeclareTargetContext() const { return IsInOpenMPDeclareTargetContext; } /// Return the number of captured regions created for an OpenMP directive. static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind); /// \brief Initialization of captured region for OpenMP region. void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); /// \brief End of OpenMP region. /// /// \param S Statement associated with the current OpenMP region. /// \param Clauses List of clauses for the current OpenMP region. /// /// \returns Statement for finished OpenMP region. StmtResult ActOnOpenMPRegionEnd(StmtResult S, ArrayRef Clauses); StmtResult ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp parallel' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp for' after parsing /// of the associated statement. StmtResult ActOnOpenMPForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp for simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp sections' after parsing /// of the associated statement. StmtResult ActOnOpenMPSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp section' after parsing of the /// associated statement. StmtResult ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp single' after parsing of the /// associated statement. StmtResult ActOnOpenMPSingleDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp master' after parsing of the /// associated statement. StmtResult ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp critical' after parsing of the /// associated statement. StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp parallel for' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp parallel sections' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp task' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp taskyield'. StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp barrier'. StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp taskwait'. StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp taskgroup'. StmtResult ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp flush'. StmtResult ActOnOpenMPFlushDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp ordered' after parsing of the /// associated statement. StmtResult ActOnOpenMPOrderedDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp atomic' after parsing of the /// associated statement. StmtResult ActOnOpenMPAtomicDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target data' after parsing of /// the associated statement. StmtResult ActOnOpenMPTargetDataDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target enter data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetEnterDataDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target exit data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetExitDataDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target parallel' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTeamsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp cancellation point'. StmtResult ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// \brief Called on well-formed '\#pragma omp cancel'. StmtResult ActOnOpenMPCancelDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// \brief Called on well-formed '\#pragma omp taskloop' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskLoopDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp taskloop simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp distribute' after parsing /// of the associated statement. StmtResult ActOnOpenMPDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp target update'. StmtResult ActOnOpenMPTargetUpdateDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp distribute parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp target parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp target simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPTargetSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute' after parsing of /// the associated statement. StmtResult ActOnOpenMPTeamsDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPTeamsDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPTeamsDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute parallel for' /// after parsing of the associated statement. StmtResult ActOnOpenMPTeamsDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetTeamsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target teams distribute' after parsing /// of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute parallel for' /// after parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute parallel for /// simd' after parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Checks correctness of linear modifiers. bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, SourceLocation LinLoc); /// Checks that the specified declaration matches requirements for the linear /// decls. bool CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc, OpenMPLinearClauseKind LinKind, QualType Type); /// \brief Called on well-formed '\#pragma omp declare simd' after parsing of /// the associated method/function. DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective( DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen, ArrayRef Uniforms, ArrayRef Aligneds, ArrayRef Alignments, ArrayRef Linears, ArrayRef LinModifiers, ArrayRef Steps, SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'if' clause. OMPClause *ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation NameModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'final' clause. OMPClause *ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'num_threads' clause. OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'safelen' clause. OMPClause *ActOnOpenMPSafelenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'simdlen' clause. OMPClause *ActOnOpenMPSimdlenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'collapse' clause. OMPClause *ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'ordered' clause. OMPClause * ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, SourceLocation LParenLoc = SourceLocation(), Expr *NumForLoops = nullptr); /// \brief Called on well-formed 'grainsize' clause. OMPClause *ActOnOpenMPGrainsizeClause(Expr *Size, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'num_tasks' clause. OMPClause *ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'hint' clause. OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'default' clause. OMPClause *ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'proc_bind' clause. OMPClause *ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef Arguments, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, ArrayRef ArgumentsLoc, SourceLocation DelimLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'schedule' clause. OMPClause *ActOnOpenMPScheduleClause( OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'nowait' clause. OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'untied' clause. OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'mergeable' clause. OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'read' clause. OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'write' clause. OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'update' clause. OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'capture' clause. OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'seq_cst' clause. OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'threads' clause. OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'simd' clause. OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'nogroup' clause. OMPClause *ActOnOpenMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef Vars, Expr *TailExpr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation DepLinMapLoc); /// \brief Called on well-formed 'private' clause. OMPClause *ActOnOpenMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'firstprivate' clause. OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'lastprivate' clause. OMPClause *ActOnOpenMPLastprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'shared' clause. OMPClause *ActOnOpenMPSharedClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'reduction' clause. OMPClause *ActOnOpenMPReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// \brief Called on well-formed 'linear' clause. OMPClause * ActOnOpenMPLinearClause(ArrayRef VarList, Expr *Step, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind, SourceLocation LinLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'aligned' clause. OMPClause *ActOnOpenMPAlignedClause(ArrayRef VarList, Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'copyin' clause. OMPClause *ActOnOpenMPCopyinClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'copyprivate' clause. OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'flush' pseudo clause. OMPClause *ActOnOpenMPFlushClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'depend' clause. OMPClause * ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'device' clause. OMPClause *ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'map' clause. OMPClause * ActOnOpenMPMapClause(OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'num_teams' clause. OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'thread_limit' clause. OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'priority' clause. OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'dist_schedule' clause. OMPClause *ActOnOpenMPDistScheduleClause( OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'defaultmap' clause. OMPClause *ActOnOpenMPDefaultmapClause( OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KindLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'to' clause. OMPClause *ActOnOpenMPToClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'from' clause. OMPClause *ActOnOpenMPFromClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'use_device_ptr' clause. OMPClause *ActOnOpenMPUseDevicePtrClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'is_device_ptr' clause. OMPClause *ActOnOpenMPIsDevicePtrClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief The kind of conversion being performed. enum CheckedConversionKind { /// \brief An implicit conversion. CCK_ImplicitConversion, /// \brief A C-style cast. CCK_CStyleCast, /// \brief A functional-style cast. CCK_FunctionalCast, /// \brief A cast other than a C-style cast. CCK_OtherCast }; /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, ExprValueKind VK = VK_RValue, const CXXCastPath *BasePath = nullptr, CheckedConversionKind CCK = CCK_ImplicitConversion); /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding /// to the conversion from scalar type ScalarTy to the Boolean type. static CastKind ScalarTypeToBooleanCastKind(QualType ScalarTy); /// IgnoredValueConversions - Given that an expression's result is /// syntactically ignored, perform any conversions that are /// required. ExprResult IgnoredValueConversions(Expr *E); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). ExprResult UsualUnaryConversions(Expr *E); /// CallExprUnaryConversions - a special case of an unary conversion /// performed on a function designator of a call expression. ExprResult CallExprUnaryConversions(Expr *E); // DefaultFunctionArrayConversion - converts functions and arrays // to their respective pointers (C99 6.3.2.1). ExprResult DefaultFunctionArrayConversion(Expr *E, bool Diagnose = true); // DefaultFunctionArrayLvalueConversion - converts functions and // arrays to their respective pointers and performs the // lvalue-to-rvalue conversion. ExprResult DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose = true); // DefaultLvalueConversion - performs lvalue-to-rvalue conversion on // the operand. This is DefaultFunctionArrayLvalueConversion, // except that it assumes the operand isn't of function or array // type. ExprResult DefaultLvalueConversion(Expr *E); // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that // do not have a prototype. Integer promotions are performed on each // argument, and arguments that have type float are promoted to double. ExprResult DefaultArgumentPromotion(Expr *E); /// If \p E is a prvalue denoting an unmaterialized temporary, materialize /// it as an xvalue. In C++98, the result will still be a prvalue, because /// we don't have xvalues there. ExprResult TemporaryMaterializationConversion(Expr *E); // Used for emitting the right warning by DefaultVariadicArgumentPromotion enum VariadicCallType { VariadicFunction, VariadicBlock, VariadicMethod, VariadicConstructor, VariadicDoesNotApply }; VariadicCallType getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr *Fn); // Used for determining in which context a type is allowed to be passed to a // vararg function. enum VarArgKind { VAK_Valid, VAK_ValidInCXX11, VAK_Undefined, VAK_MSVCUndefined, VAK_Invalid }; // Determines which VarArgKind fits an expression. VarArgKind isValidVarArgType(const QualType &Ty); /// Check to see if the given expression is a valid argument to a variadic /// function, issuing a diagnostic if not. void checkVariadicArgument(const Expr *E, VariadicCallType CT); /// Check to see if a given expression could have '.c_str()' called on it. bool hasCStrMethod(const Expr *E); /// GatherArgumentsForCall - Collector argument expressions for various /// form of call prototypes. bool GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, const FunctionProtoType *Proto, unsigned FirstParam, ArrayRef Args, SmallVectorImpl &AllArgs, VariadicCallType CallType = VariadicDoesNotApply, bool AllowExplicit = false, bool IsListInitialization = false); // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will create a runtime trap if the resulting type is not a POD type. ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl); // UsualArithmeticConversions - performs the UsualUnaryConversions on it's // operands and then handles various conversions that are common to binary // operators (C99 6.3.1.8). If both operands aren't arithmetic, this // routine returns the first non-arithmetic type found. The client is // responsible for emitting appropriate error diagnostics. QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, bool IsCompAssign = false); /// AssignConvertType - All of the 'assignment' semantic checks return this /// enum to indicate whether the assignment was allowed. These checks are /// done for simple assignments, as well as initialization, return from /// function, argument passing, etc. The query is phrased in terms of a /// source and destination type. enum AssignConvertType { /// Compatible - the types are compatible according to the standard. Compatible, /// PointerToInt - The assignment converts a pointer to an int, which we /// accept as an extension. PointerToInt, /// IntToPointer - The assignment converts an int to a pointer, which we /// accept as an extension. IntToPointer, /// FunctionVoidPointer - The assignment is between a function pointer and /// void*, which the standard doesn't allow, but we accept as an extension. FunctionVoidPointer, /// IncompatiblePointer - The assignment is between two pointers types that /// are not compatible, but we accept them as an extension. IncompatiblePointer, /// IncompatiblePointerSign - The assignment is between two pointers types /// which point to integers which have a different sign, but are otherwise /// identical. This is a subset of the above, but broken out because it's by /// far the most common case of incompatible pointers. IncompatiblePointerSign, /// CompatiblePointerDiscardsQualifiers - The assignment discards /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, /// IncompatiblePointerDiscardsQualifiers - The assignment /// discards qualifiers that we don't permit to be discarded, /// like address spaces. IncompatiblePointerDiscardsQualifiers, /// IncompatibleNestedPointerQualifiers - The assignment is between two /// nested pointer types, and the qualifiers other than the first two /// levels differ e.g. char ** -> const char **, but we accept them as an /// extension. IncompatibleNestedPointerQualifiers, /// IncompatibleVectors - The assignment is between two vector types that /// have the same size, which we accept as an extension. IncompatibleVectors, /// IntToBlockPointer - The assignment converts an int to a block /// pointer. We disallow this. IntToBlockPointer, /// IncompatibleBlockPointer - The assignment is between two block /// pointers types that are not compatible. IncompatibleBlockPointer, /// IncompatibleObjCQualifiedId - The assignment is between a qualified /// id type and something else (that is incompatible with it). For example, /// "id " = "Foo *", where "Foo *" doesn't implement the XXX protocol. IncompatibleObjCQualifiedId, /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an /// object with __weak qualifier. IncompatibleObjCWeakRef, /// Incompatible - We reject this conversion outright, it is invalid to /// represent it in the AST. Incompatible }; /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the /// conversion was invalid or false if the conversion was accepted. bool DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, Expr *SrcExpr, AssignmentAction Action, bool *Complained = nullptr); /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag /// enum. If AllowMask is true, then we also allow the complement of a valid /// value, to be used as a mask. bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, bool AllowMask) const; /// DiagnoseAssignmentEnum - Warn if assignment to enum is a constant /// integer not in the range of enum values. void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, Expr *SrcExpr); /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. /// C99 6.5.16. AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, QualType LHSType, QualType RHSType); /// Check assignment constraints and optionally prepare for a conversion of /// the RHS to the LHS type. The conversion is prepared for if ConvertRHS /// is true. AssignConvertType CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, CastKind &Kind, bool ConvertRHS = true); /// Check assignment constraints for an assignment of RHS to LHSType. /// /// \param LHSType The destination type for the assignment. /// \param RHS The source expression for the assignment. /// \param Diagnose If \c true, diagnostics may be produced when checking /// for assignability. If a diagnostic is produced, \p RHS will be /// set to ExprError(). Note that this function may still return /// without producing a diagnostic, even for an invalid assignment. /// \param DiagnoseCFAudited If \c true, the target is a function parameter /// in an audited Core Foundation API and does not need to be checked /// for ARC retain issues. /// \param ConvertRHS If \c true, \p RHS will be updated to model the /// conversions necessary to perform the assignment. If \c false, /// \p Diagnose must also be \c false. AssignConvertType CheckSingleAssignmentConstraints( QualType LHSType, ExprResult &RHS, bool Diagnose = true, bool DiagnoseCFAudited = false, bool ConvertRHS = true); // \brief If the lhs type is a transparent union, check whether we // can initialize the transparent union with the given expression. AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS); bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit = false); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, ImplicitConversionSequence& ICS); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence& ICS, AssignmentAction Action, CheckedConversionKind CCK = CCK_ImplicitConversion); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, CheckedConversionKind CCK); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). /// type checking binary operators (subroutines of CreateBuiltinBinOp). QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS); QualType InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS); QualType CheckPointerToMemberOperands( // C++ 5.5 ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation OpLoc, bool isIndirect); QualType CheckMultiplyDivideOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool IsDivide); QualType CheckRemainderOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign = false); QualType CheckAdditionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, QualType* CompLHSTy = nullptr); QualType CheckSubtractionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy = nullptr); QualType CheckShiftOperands( // C99 6.5.7 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool IsCompAssign = false); QualType CheckCompareOperands( // C99 6.5.8/9 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool isRelational); QualType CheckBitwiseOperands( // C99 6.5.[10...12] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckLogicalOperands( // C99 6.5.[13,14] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); // CheckAssignmentOperands is used for both simple and compound assignment. // For simple assignment, pass both expressions and a null converted type. // For compound assignment, pass both expressions and the converted type. QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType); ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opcode, Expr *Op); ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opcode, Expr *LHS, Expr *RHS); ExprResult checkPseudoObjectRValue(Expr *E); Expr *recreateSyntacticForm(PseudoObjectExpr *E); QualType CheckConditionalOperands( // C99 6.5.15 ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 ExprResult &cond, ExprResult &lhs, ExprResult &rhs, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool ConvertArgs = true); QualType FindCompositePointerType(SourceLocation Loc, ExprResult &E1, ExprResult &E2, bool ConvertArgs = true) { Expr *E1Tmp = E1.get(), *E2Tmp = E2.get(); QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, ConvertArgs); E1 = E1Tmp; E2 = E2Tmp; return Composite; } QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc); bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, SourceLocation QuestionLoc); void DiagnoseAlwaysNonNullPointer(Expr *E, Expr::NullPointerConstantKind NullType, bool IsEqual, SourceRange Range); /// type checking for vector binary operators. QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, bool AllowBoolConversion); QualType GetSignedVectorType(QualType V); QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool isRelational); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc); bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); bool isLaxVectorConversion(QualType srcType, QualType destType); /// type checking declaration initializers (C99 6.7.8) bool CheckForConstantInitializer(Expr *e, QualType t); // type checking C++ declaration initializers (C++ [dcl.init]). /// ReferenceCompareResult - Expresses the result of comparing two /// types (cv1 T1 and cv2 T2) to determine their compatibility for the /// purposes of initialization by reference (C++ [dcl.init.ref]p4). enum ReferenceCompareResult { /// Ref_Incompatible - The two types are incompatible, so direct /// reference binding is not possible. Ref_Incompatible = 0, /// Ref_Related - The two types are reference-related, which means /// that their unqualified forms (T1 and T2) are either the same /// or T1 is a base class of T2. Ref_Related, /// Ref_Compatible - The two types are reference-compatible. Ref_Compatible }; ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2, bool &DerivedToBase, bool &ObjCConversion, bool &ObjCLifetimeConversion); ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, Expr *CastExpr, CastKind &CastKind, ExprValueKind &VK, CXXCastPath &Path); /// \brief Force an expression with unknown-type to an expression of the /// given type. ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); /// \brief Type-check an expression that's being passed to an /// __unknown_anytype parameter. ExprResult checkUnknownAnyArg(SourceLocation callLoc, Expr *result, QualType ¶mType); // CheckVectorCast - check type constraints for vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size. // returns true if the cast is invalid bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind); /// \brief Prepare `SplattedExpr` for a vector splat operation, adding /// implicit casts if necessary. ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr); // CheckExtVectorCast - check type constraints for extended vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size, // or vectors and the element type of that vector. // returns the cast expr ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, CastKind &Kind); ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type, SourceLocation LParenLoc, Expr *CastExpr, SourceLocation RParenLoc); enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error }; /// \brief Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds for ARC and Weak. ARCConversionResult CheckObjCConversion(SourceRange castRange, QualType castType, Expr *&op, CheckedConversionKind CCK, bool Diagnose = true, bool DiagnoseCFAudited = false, BinaryOperatorKind Opc = BO_PtrMemD ); Expr *stripARCUnbridgedCast(Expr *e); void diagnoseARCUnbridgedCast(Expr *e); bool CheckObjCARCUnavailableWeakConversion(QualType castType, QualType ExprType); /// checkRetainCycles - Check whether an Objective-C message send /// might create an obvious retain cycle. void checkRetainCycles(ObjCMessageExpr *msg); void checkRetainCycles(Expr *receiver, Expr *argument); void checkRetainCycles(VarDecl *Var, Expr *Init); /// checkUnsafeAssigns - Check whether +1 expr is being assigned /// to weak/__unsafe_unretained type. bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned /// to weak/__unsafe_unretained expression. void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. /// \param [out] ReturnType - The return type of the send. /// \return true iff there were any incompatible types. bool CheckMessageArgumentTypes(QualType ReceiverType, MultiExprArg Args, Selector Sel, ArrayRef SelectorLocs, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType, ExprValueKind &VK); /// \brief Determine the result of a message send expression based on /// the type of the receiver, the method expected to receive the message, /// and the form of the message send. QualType getMessageSendResultType(QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage); /// \brief If the given expression involves a message send to a method /// with a related result type, emit a note describing what happened. void EmitRelatedResultTypeNote(const Expr *E); /// \brief Given that we had incompatible pointer types in a return /// statement, check whether we're in a method with a related result /// type, and if so, emit a note describing what happened. void EmitRelatedResultTypeNoteForReturn(QualType destType); class ConditionResult { Decl *ConditionVar; FullExprArg Condition; bool Invalid; bool HasKnownValue; bool KnownValue; friend class Sema; ConditionResult(Sema &S, Decl *ConditionVar, FullExprArg Condition, bool IsConstexpr) : ConditionVar(ConditionVar), Condition(Condition), Invalid(false), HasKnownValue(IsConstexpr && Condition.get() && !Condition.get()->isValueDependent()), KnownValue(HasKnownValue && !!Condition.get()->EvaluateKnownConstInt(S.Context)) {} explicit ConditionResult(bool Invalid) : ConditionVar(nullptr), Condition(nullptr), Invalid(Invalid), HasKnownValue(false), KnownValue(false) {} public: ConditionResult() : ConditionResult(false) {} bool isInvalid() const { return Invalid; } std::pair get() const { return std::make_pair(cast_or_null(ConditionVar), Condition.get()); } llvm::Optional getKnownValue() const { if (!HasKnownValue) return None; return KnownValue; } }; static ConditionResult ConditionError() { return ConditionResult(true); } enum class ConditionKind { Boolean, ///< A boolean condition, from 'if', 'while', 'for', or 'do'. ConstexprIf, ///< A constant boolean condition from 'if constexpr'. Switch ///< An integral condition for a 'switch' statement. }; ConditionResult ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, ConditionKind CK); ConditionResult ActOnConditionVariable(Decl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK); DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); ExprResult CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK); ExprResult CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond); /// CheckBooleanCondition - Diagnose problems involving the use of /// the given expression as a boolean condition (e.g. in an if /// statement). Also performs the standard function and array /// decays, possibly changing the input variable. /// /// \param Loc - A location associated with the condition, e.g. the /// 'if' keyword. /// \return true iff there were any errors ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E, bool IsConstexpr = false); /// DiagnoseAssignmentAsCondition - Given that an expression is /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); /// \brief Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE); /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. ExprResult CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr = false); /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, unsigned NewWidth, bool NewSign, SourceLocation Loc, unsigned DiagID); /// Checks that the Objective-C declaration is declared in the global scope. /// Emits an error and marks the declaration as invalid if it's not declared /// in the global scope. bool CheckObjCDeclScope(Decl *D); /// \brief Abstract base class used for diagnosing integer constant /// expression violations. class VerifyICEDiagnoser { public: bool Suppress; VerifyICEDiagnoser(bool Suppress = false) : Suppress(Suppress) { } virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) =0; virtual void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR); virtual ~VerifyICEDiagnoser() { } }; /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE, /// and reports the appropriate diagnostics. Returns false on success. /// Can optionally return the value of the expression. ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, VerifyICEDiagnoser &Diagnoser, bool AllowFold = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, unsigned DiagID, bool AllowFold = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result = nullptr); /// VerifyBitField - verifies that a bit field expression is an ICE and has /// the correct width, and that the field type is valid. /// Returns false on success. /// Can optionally return whether the bit-field is of width 0 ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, bool IsMsStruct, Expr *BitWidth, bool *ZeroWidth = nullptr); private: unsigned ForceCUDAHostDeviceDepth = 0; public: /// Increments our count of the number of times we've seen a pragma forcing /// functions to be __host__ __device__. So long as this count is greater /// than zero, all functions encountered will be __host__ __device__. void PushForceCUDAHostDevice(); /// Decrements our count of the number of times we've seen a pragma forcing /// functions to be __host__ __device__. Returns false if the count is 0 /// before incrementing, so you can emit an error. bool PopForceCUDAHostDevice(); /// Diagnostics that are emitted only if we discover that the given function /// must be codegen'ed. Because handling these correctly adds overhead to /// compilation, this is currently only enabled for CUDA compilations. llvm::DenseMap, std::vector> CUDADeferredDiags; /// A pair of a canonical FunctionDecl and a SourceLocation. When used as the /// key in a hashtable, both the FD and location are hashed. struct FunctionDeclAndLoc { CanonicalDeclPtr FD; SourceLocation Loc; }; /// FunctionDecls and SourceLocations for which CheckCUDACall has emitted a /// (maybe deferred) "bad call" diagnostic. We use this to avoid emitting the /// same deferred diag twice. llvm::DenseSet LocsWithCUDACallDiags; /// An inverse call graph, mapping known-emitted functions to one of their /// known-emitted callers (plus the location of the call). /// /// Functions that we can tell a priori must be emitted aren't added to this /// map. llvm::DenseMap, /* Caller = */ FunctionDeclAndLoc> CUDAKnownEmittedFns; /// A partial call graph maintained during CUDA compilation to support /// deferred diagnostics. /// /// Functions are only added here if, at the time they're considered, they are /// not known-emitted. As soon as we discover that a function is /// known-emitted, we remove it and everything it transitively calls from this /// set and add those functions to CUDAKnownEmittedFns. llvm::DenseMap, /* Callees = */ llvm::MapVector, SourceLocation>> CUDACallGraph; /// Diagnostic builder for CUDA errors which may or may not be deferred. /// /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) /// which are not allowed to appear inside __device__ functions and are /// allowed to appear in __host__ __device__ functions only if the host+device /// function is never codegen'ed. /// /// To handle this, we use the notion of "deferred diagnostics", where we /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. /// /// This class lets you emit either a regular diagnostic, a deferred /// diagnostic, or no diagnostic at all, according to an argument you pass to /// its constructor, thus simplifying the process of creating these "maybe /// deferred" diagnostics. class CUDADiagBuilder { public: enum Kind { /// Emit no diagnostics. K_Nop, /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). K_Immediate, /// Emit the diagnostic immediately, and, if it's a warning or error, also /// emit a call stack showing how this function can be reached by an a /// priori known-emitted function. K_ImmediateWithCallStack, /// Create a deferred diagnostic, which is emitted only if the function /// it's attached to is codegen'ed. Also emit a call stack as with /// K_ImmediateWithCallStack. K_Deferred }; CUDADiagBuilder(Kind K, SourceLocation Loc, unsigned DiagID, FunctionDecl *Fn, Sema &S); ~CUDADiagBuilder(); /// Convertible to bool: True if we immediately emitted an error, false if /// we didn't emit an error or we created a deferred error. /// /// Example usage: /// /// if (CUDADiagBuilder(...) << foo << bar) /// return ExprError(); /// /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably /// want to use these instead of creating a CUDADiagBuilder yourself. operator bool() const { return ImmediateDiag.hasValue(); } template friend const CUDADiagBuilder &operator<<(const CUDADiagBuilder &Diag, const T &Value) { if (Diag.ImmediateDiag.hasValue()) *Diag.ImmediateDiag << Value; else if (Diag.PartialDiag.hasValue()) *Diag.PartialDiag << Value; return Diag; } private: Sema &S; SourceLocation Loc; unsigned DiagID; FunctionDecl *Fn; bool ShowCallStack; // Invariant: At most one of these Optionals has a value. // FIXME: Switch these to a Variant once that exists. llvm::Optional ImmediateDiag; llvm::Optional PartialDiag; }; /// Creates a CUDADiagBuilder that emits the diagnostic if the current context /// is "used as device code". /// /// - If CurContext is a __host__ function, does not emit any diagnostics. /// - If CurContext is a __device__ or __global__ function, emits the /// diagnostics immediately. /// - If CurContext is a __host__ __device__ function and we are compiling for /// the device, creates a diagnostic which is emitted if and when we realize /// that the function will be codegen'ed. /// /// Example usage: /// /// // Variable-length arrays are not allowed in CUDA device code. /// if (CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget()) /// return ExprError(); /// // Otherwise, continue parsing as normal. CUDADiagBuilder CUDADiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); /// Creates a CUDADiagBuilder that emits the diagnostic if the current context /// is "used as host code". /// /// Same as CUDADiagIfDeviceCode, with "host" and "device" switched. CUDADiagBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID); enum CUDAFunctionTarget { CFT_Device, CFT_Global, CFT_Host, CFT_HostDevice, CFT_InvalidTarget }; /// Determines whether the given function is a CUDA device/host/kernel/etc. /// function. /// /// Use this rather than examining the function's attributes yourself -- you /// will get it wrong. Returns CFT_Host if D is null. CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, bool IgnoreImplicitHDAttr = false); CUDAFunctionTarget IdentifyCUDATarget(const AttributeList *Attr); /// Gets the CUDA target for the current context. CUDAFunctionTarget CurrentCUDATarget() { return IdentifyCUDATarget(dyn_cast(CurContext)); } // CUDA function call preference. Must be ordered numerically from // worst to best. enum CUDAFunctionPreference { CFP_Never, // Invalid caller/callee combination. CFP_WrongSide, // Calls from host-device to host or device // function that do not match current compilation // mode. CFP_HostDevice, // Any calls to host/device functions. CFP_SameSide, // Calls from host-device to host or device // function matching current compilation mode. CFP_Native, // host-to-host or device-to-device calls. }; /// Identifies relative preference of a given Caller/Callee /// combination, based on their host/device attributes. /// \param Caller function which needs address of \p Callee. /// nullptr in case of global context. /// \param Callee target function /// /// \returns preference value for particular Caller/Callee combination. CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee); /// Determines whether Caller may invoke Callee, based on their CUDA /// host/device attributes. Returns false if the call is not allowed. /// /// Note: Will return true for CFP_WrongSide calls. These may appear in /// semantically correct CUDA programs, but only if they're never codegen'ed. bool IsAllowedCUDACall(const FunctionDecl *Caller, const FunctionDecl *Callee) { return IdentifyCUDAPreference(Caller, Callee) != CFP_Never; } /// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, /// depending on FD and the current compilation settings. void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD, const LookupResult &Previous); public: /// Check whether we're allowed to call Callee from the current context. /// /// - If the call is never allowed in a semantically-correct program /// (CFP_Never), emits an error and returns false. /// /// - If the call is allowed in semantically-correct programs, but only if /// it's never codegen'ed (CFP_WrongSide), creates a deferred diagnostic to /// be emitted if and when the caller is codegen'ed, and returns true. /// /// Will only create deferred diagnostics for a given SourceLocation once, /// so you can safely call this multiple times without generating duplicate /// deferred errors. /// /// - Otherwise, returns true without emitting any diagnostics. bool CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee); /// Set __device__ or __host__ __device__ attributes on the given lambda /// operator() method. /// /// CUDA lambdas declared inside __device__ or __global__ functions inherit /// the __device__ attribute. Similarly, lambdas inside __host__ __device__ /// functions become __host__ __device__ themselves. void CUDASetLambdaAttrs(CXXMethodDecl *Method); /// Finds a function in \p Matches with highest calling priority /// from \p Caller context and erases all functions with lower /// calling priority. void EraseUnwantedCUDAMatches( const FunctionDecl *Caller, SmallVectorImpl> &Matches); /// Given a implicit special member, infer its CUDA target from the /// calls it needs to make to underlying base/field special members. /// \param ClassDecl the class for which the member is being created. /// \param CSM the kind of special member. /// \param MemberDecl the special member itself. /// \param ConstRHS true if this is a copy operation with a const object on /// its RHS. /// \param Diagnose true if this call should emit diagnostics. /// \return true if there was an error inferring. /// The result of this call is implicit CUDA target attribute(s) attached to /// the member declaration. bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXSpecialMember CSM, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose); /// \return true if \p CD can be considered empty according to CUDA /// (E.2.3.1 in CUDA 7.5 Programming guide). bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD); bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD); /// Check whether NewFD is a valid overload for CUDA. Emits /// diagnostics and invalidates NewFD if not. void checkCUDATargetOverload(FunctionDecl *NewFD, const LookupResult &Previous); /// Copies target attributes from the template TD to the function FD. void inheritCUDATargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD); /// \name Code completion //@{ /// \brief Describes the context in which code completion occurs. enum ParserCompletionContext { /// \brief Code completion occurs at top-level or namespace context. PCC_Namespace, /// \brief Code completion occurs within a class, struct, or union. PCC_Class, /// \brief Code completion occurs within an Objective-C interface, protocol, /// or category. PCC_ObjCInterface, /// \brief Code completion occurs within an Objective-C implementation or /// category implementation PCC_ObjCImplementation, /// \brief Code completion occurs within the list of instance variables /// in an Objective-C interface, protocol, category, or implementation. PCC_ObjCInstanceVariableList, /// \brief Code completion occurs following one or more template /// headers. PCC_Template, /// \brief Code completion occurs following one or more template /// headers within a class. PCC_MemberTemplate, /// \brief Code completion occurs within an expression. PCC_Expression, /// \brief Code completion occurs within a statement, which may /// also be an expression or a declaration. PCC_Statement, /// \brief Code completion occurs at the beginning of the /// initialization statement (or expression) in a for loop. PCC_ForInit, /// \brief Code completion occurs within the condition of an if, /// while, switch, or for statement. PCC_Condition, /// \brief Code completion occurs within the body of a function on a /// recovery path, where we do not have a specific handle on our position /// in the grammar. PCC_RecoveryInFunction, /// \brief Code completion occurs where only a type is permitted. PCC_Type, /// \brief Code completion occurs in a parenthesized expression, which /// might also be a type cast. PCC_ParenthesizedExpression, /// \brief Code completion occurs within a sequence of declaration /// specifiers within a function, method, or block. PCC_LocalDeclarationSpecifiers }; void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path); void CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext); void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, bool AllowNonIdentifiers, bool AllowNestedNameSpecifiers); struct CodeCompleteExpressionData; void CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data); void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool IsArrow, bool IsBaseExprStatement); void CodeCompletePostfixExpression(Scope *S, ExprResult LHS); void CodeCompleteTag(Scope *S, unsigned TagSpec); void CodeCompleteTypeQualifiers(DeclSpec &DS); void CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D, const VirtSpecifiers *VS = nullptr); void CodeCompleteBracketDeclarator(Scope *S); void CodeCompleteCase(Scope *S); void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args); void CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc, ArrayRef Args); void CodeCompleteInitializer(Scope *S, Decl *D); void CodeCompleteReturn(Scope *S); void CodeCompleteAfterIf(Scope *S); void CodeCompleteAssignmentRHS(Scope *S, Expr *LHS); void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext); void CodeCompleteUsing(Scope *S); void CodeCompleteUsingDirective(Scope *S); void CodeCompleteNamespaceDecl(Scope *S); void CodeCompleteNamespaceAliasDecl(Scope *S); void CodeCompleteOperatorName(Scope *S); void CodeCompleteConstructorInitializer( Decl *Constructor, ArrayRef Initializers); void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, bool AfterAmpersand); void CodeCompleteObjCAtDirective(Scope *S); void CodeCompleteObjCAtVisibility(Scope *S); void CodeCompleteObjCAtStatement(Scope *S); void CodeCompleteObjCAtExpression(Scope *S); void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); void CodeCompleteObjCPropertyGetter(Scope *S); void CodeCompleteObjCPropertySetter(Scope *S); void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, bool IsParameter); void CodeCompleteObjCMessageReceiver(Scope *S); void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, ArrayRef SelIdents, bool AtArgumentExpression); void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper = false); void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, ArrayRef SelIdents, bool AtArgumentExpression, ObjCInterfaceDecl *Super = nullptr); void CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar); void CodeCompleteObjCSelector(Scope *S, ArrayRef SelIdents); void CodeCompleteObjCProtocolReferences( ArrayRef Protocols); void CodeCompleteObjCProtocolDecl(Scope *S); void CodeCompleteObjCInterfaceDecl(Scope *S); void CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCImplementationDecl(Scope *S); void CodeCompleteObjCInterfaceCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCImplementationCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCPropertyDefinition(Scope *S); void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName); void CodeCompleteObjCMethodDecl(Scope *S, bool IsInstanceMethod, ParsedType ReturnType); void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnType, ArrayRef SelIdents); void CodeCompleteObjCClassPropertyRefExpr(Scope *S, IdentifierInfo &ClassName, SourceLocation ClassNameLoc, bool IsBaseExprStatement); void CodeCompletePreprocessorDirective(bool InConditional); void CodeCompleteInPreprocessorConditionalExclusion(Scope *S); void CodeCompletePreprocessorMacroName(bool IsDefinition); void CodeCompletePreprocessorExpression(); void CodeCompletePreprocessorMacroArgument(Scope *S, IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned Argument); void CodeCompleteNaturalLanguage(); void CodeCompleteAvailabilityPlatformName(); void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, SmallVectorImpl &Results); //@} //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system public: SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const; private: void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE=nullptr, bool AllowOnePastEnd=true, bool IndexNegated=false); void CheckArrayAccess(const Expr *E); // Used to grab the relevant information from a FormatAttr and a // FunctionDeclaration. struct FormatStringInfo { unsigned FormatIdx; unsigned FirstDataArg; bool HasVAListArg; }; static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, FormatStringInfo *FSI); bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto); bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, ArrayRef Args); bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto); bool CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto); void CheckConstructorCall(FunctionDecl *FDecl, ArrayRef Args, const FunctionProtoType *Proto, SourceLocation Loc); void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, const Expr *ThisArg, ArrayRef Args, bool IsMemberFunction, SourceLocation Loc, SourceRange Range, VariadicCallType CallType); bool CheckObjCString(Expr *Arg); ExprResult CheckOSLogFormatStringArg(Expr *Arg); ExprResult CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall); bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, unsigned MaxWidth); bool CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStartARM(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); bool SemaBuiltinOSLogFormat(CallExpr *TheCall); public: // Used by C++ template instantiation. ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, SourceLocation BuiltinLoc, SourceLocation RParenLoc); private: bool SemaBuiltinPrefetch(CallExpr *TheCall); bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall); bool SemaBuiltinAssume(CallExpr *TheCall); bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); bool SemaBuiltinSetjmp(CallExpr *TheCall); ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High); bool SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, unsigned Multiple); bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, unsigned ExpectedFieldNum, bool AllowName); public: enum FormatStringType { FST_Scanf, FST_Printf, FST_NSString, FST_Strftime, FST_Strfmon, FST_Kprintf, FST_FreeBSDKPrintf, FST_OSTrace, FST_OSLog, FST_Unknown }; static FormatStringType GetFormatStringType(const FormatAttr *Format); bool FormatStringHasSArg(const StringLiteral *FExpr); static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx); private: bool CheckFormatArguments(const FormatAttr *Format, ArrayRef Args, bool IsCXXMember, VariadicCallType CallType, SourceLocation Loc, SourceRange Range, llvm::SmallBitVector &CheckedVarArgs); bool CheckFormatArguments(ArrayRef Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, VariadicCallType CallType, SourceLocation Loc, SourceRange range, llvm::SmallBitVector &CheckedVarArgs); void CheckAbsoluteValueFunction(const CallExpr *Call, const FunctionDecl *FDecl); void CheckMaxUnsignedZero(const CallExpr *Call, const FunctionDecl *FDecl); void CheckMemaccessArguments(const CallExpr *Call, unsigned BId, IdentifierInfo *FnName); void CheckStrlcpycatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckStrncatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod = false, const AttrVec *Attrs = nullptr, const FunctionDecl *FD = nullptr); void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); void CheckBoolLikeConversion(Expr *E, SourceLocation CC); void CheckUnsequencedOperations(Expr *E); /// \brief Perform semantic checks on a completed expression. This will either /// be a full-expression or a default argument expression. void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(), bool IsConstexpr = false); void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, Expr *Init); /// Check if there is a field shadowing. void CheckShadowInheritedFields(const SourceLocation &Loc, DeclarationName FieldName, const CXXRecordDecl *RD); /// \brief Check if the given expression contains 'break' or 'continue' /// statement that produces control flow different from GCC. void CheckBreakContinueBinding(Expr *E); /// \brief Check whether receiver is mutable ObjC container which /// attempts to add itself into the container void CheckObjCCircularContainer(ObjCMessageExpr *Message); void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm); public: /// \brief Register a magic integral constant to be used as a type tag. void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, bool LayoutCompatible, bool MustBeNull); struct TypeTagData { TypeTagData() {} TypeTagData(QualType Type, bool LayoutCompatible, bool MustBeNull) : Type(Type), LayoutCompatible(LayoutCompatible), MustBeNull(MustBeNull) {} QualType Type; /// If true, \c Type should be compared with other expression's types for /// layout-compatibility. unsigned LayoutCompatible : 1; unsigned MustBeNull : 1; }; /// A pair of ArgumentKind identifier and magic value. This uniquely /// identifies the magic value. typedef std::pair TypeTagMagicValue; private: /// \brief A map from magic value to type information. std::unique_ptr> TypeTagForDatatypeMagicValues; /// \brief Peform checks on a call of a function with argument_with_type_tag /// or pointer_with_type_tag attributes. void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const Expr * const *ExprArgs); /// \brief Check if we are taking the address of a packed field /// as this may be a problem if the pointer value is dereferenced. void CheckAddressOfPackedMember(Expr *rhs); /// \brief The parser's current scope. /// /// The parser maintains this state here. Scope *CurScope; mutable IdentifierInfo *Ident_super; mutable IdentifierInfo *Ident___float128; /// Nullability type specifiers. IdentifierInfo *Ident__Nonnull = nullptr; IdentifierInfo *Ident__Nullable = nullptr; IdentifierInfo *Ident__Null_unspecified = nullptr; IdentifierInfo *Ident_NSError = nullptr; protected: friend class Parser; friend class InitializationSequence; friend class ASTReader; friend class ASTDeclReader; friend class ASTWriter; public: /// Retrieve the keyword associated IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability); /// The struct behind the CFErrorRef pointer. RecordDecl *CFError = nullptr; /// Retrieve the identifier "NSError". IdentifierInfo *getNSErrorIdent(); /// \brief Retrieve the parser's current scope. /// /// This routine must only be used when it is certain that semantic analysis /// and the parser are in precisely the same context, which is not the case /// when, e.g., we are performing any kind of template instantiation. /// Therefore, the only safe places to use this scope are in the parser /// itself and in routines directly invoked from the parser and *never* from /// template substitution or instantiation. Scope *getCurScope() const { return CurScope; } void incrementMSManglingNumber() const { return CurScope->incrementMSManglingNumber(); } IdentifierInfo *getSuperIdentifier() const; IdentifierInfo *getFloat128Identifier() const; Decl *getObjCDeclContext() const; DeclContext *getCurLexicalContext() const { return OriginalLexicalContext ? OriginalLexicalContext : CurContext; } /// \brief The diagnostic we should emit for \c D, or \c AR_Available. /// /// \param D The declaration to check. Note that this may be altered to point /// to another declaration that \c D gets it's availability from. i.e., we /// walk the list of typedefs to find an availability attribute. /// /// \param Message If non-null, this will be populated with the message from /// the availability attribute that is selected. AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message); const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); // A category implicitly has the attribute of the interface. if (const ObjCCategoryDecl *CatD = dyn_cast(DC)) DC = CatD->getClassInterface(); return DC; } /// \brief To be used for checking whether the arguments being passed to /// function exceeds the number of parameters expected for it. static bool TooManyArguments(size_t NumParams, size_t NumArgs, bool PartialOverloading = false) { // We check whether we're just after a comma in code-completion. if (NumArgs > 0 && PartialOverloading) return NumArgs + 1 > NumParams; // If so, we view as an extra argument. return NumArgs > NumParams; } // Emitting members of dllexported classes is delayed until the class // (including field initializers) is fully parsed. SmallVector DelayedDllExportClasses; private: /// \brief Helper class that collects misaligned member designations and /// their location info for delayed diagnostics. struct MisalignedMember { Expr *E; RecordDecl *RD; ValueDecl *MD; CharUnits Alignment; MisalignedMember() : E(), RD(), MD(), Alignment() {} MisalignedMember(Expr *E, RecordDecl *RD, ValueDecl *MD, CharUnits Alignment) : E(E), RD(RD), MD(MD), Alignment(Alignment) {} explicit MisalignedMember(Expr *E) : MisalignedMember(E, nullptr, nullptr, CharUnits()) {} bool operator==(const MisalignedMember &m) { return this->E == m.E; } }; /// \brief Small set of gathered accesses to potentially misaligned members /// due to the packed attribute. SmallVector MisalignedMembers; /// \brief Adds an expression to the set of gathered misaligned members. void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, CharUnits Alignment); public: /// \brief Diagnoses the current set of gathered accesses. This typically /// happens at full expression level. The set is cleared after emitting the /// diagnostics. void DiagnoseMisalignedMembers(); /// \brief This function checks if the expression is in the sef of potentially /// misaligned members and it is converted to some pointer type T with lower /// or equal alignment requirements. If so it removes it. This is used when /// we do not want to diagnose such misaligned access (e.g. in conversions to /// void*). void DiscardMisalignedMemberAddress(const Type *T, Expr *E); /// \brief This function calls Action when it determines that E designates a /// misaligned member due to the packed attribute. This is used to emit /// local diagnostics like in reference binding. void RefersToMemberWithReducedAlignment( Expr *E, llvm::function_ref Action); }; /// \brief RAII object that enters a new expression evaluation context. class EnterExpressionEvaluationContext { Sema &Actions; bool Entered = true; public: EnterExpressionEvaluationContext(Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, bool IsDecltype = false, bool ShouldEnter = true) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype); } EnterExpressionEvaluationContext(Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Sema::ReuseLambdaContextDecl_t, bool IsDecltype = false) : Actions(Actions) { Actions.PushExpressionEvaluationContext(NewContext, Sema::ReuseLambdaContextDecl, IsDecltype); } enum InitListTag { InitList }; EnterExpressionEvaluationContext(Sema &Actions, InitListTag, bool ShouldEnter = true) : Actions(Actions), Entered(false) { // In C++11 onwards, narrowing checks are performed on the contents of // braced-init-lists, even when they occur within unevaluated operands. // Therefore we still need to instantiate constexpr functions used in such // a context. if (ShouldEnter && Actions.isUnevaluatedContext() && Actions.getLangOpts().CPlusPlus11) { Actions.PushExpressionEvaluationContext( Sema::ExpressionEvaluationContext::UnevaluatedList, nullptr, false); Entered = true; } } ~EnterExpressionEvaluationContext() { if (Entered) Actions.PopExpressionEvaluationContext(); } }; DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, sema::TemplateDeductionInfo &Info); /// \brief Contains a late templated function. /// Will be parsed at the end of the translation unit, used by Sema & Parser. struct LateParsedTemplate { CachedTokens Toks; /// \brief The template function declaration to be late parsed. Decl *D; }; } // end namespace clang namespace llvm { // Hash a FunctionDeclAndLoc by looking at both its FunctionDecl and its // SourceLocation. template <> struct DenseMapInfo { using FunctionDeclAndLoc = clang::Sema::FunctionDeclAndLoc; using FDBaseInfo = DenseMapInfo>; static FunctionDeclAndLoc getEmptyKey() { return {FDBaseInfo::getEmptyKey(), clang::SourceLocation()}; } static FunctionDeclAndLoc getTombstoneKey() { return {FDBaseInfo::getTombstoneKey(), clang::SourceLocation()}; } static unsigned getHashValue(const FunctionDeclAndLoc &FDL) { return hash_combine(FDBaseInfo::getHashValue(FDL.FD), FDL.Loc.getRawEncoding()); } static bool isEqual(const FunctionDeclAndLoc &LHS, const FunctionDeclAndLoc &RHS) { return LHS.FD == RHS.FD && LHS.Loc == RHS.Loc; } }; } // namespace llvm #endif Index: vendor/clang/dist/lib/AST/ASTDumper.cpp =================================================================== --- vendor/clang/dist/lib/AST/ASTDumper.cpp (revision 318415) +++ vendor/clang/dist/lib/AST/ASTDumper.cpp (revision 318416) @@ -1,2597 +1,2597 @@ //===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the AST dump methods, which dump out the // AST in a form that exposes type details and other fields. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/CommentVisitor.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclLookups.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/LocInfoType.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::comments; //===----------------------------------------------------------------------===// // ASTDumper Visitor //===----------------------------------------------------------------------===// namespace { // Colors used for various parts of the AST dump // Do not use bold yellow for any text. It is hard to read on white screens. struct TerminalColor { raw_ostream::Colors Color; bool Bold; }; // Red - CastColor // Green - TypeColor // Bold Green - DeclKindNameColor, UndeserializedColor // Yellow - AddressColor, LocationColor // Blue - CommentColor, NullColor, IndentColor // Bold Blue - AttrColor // Bold Magenta - StmtColor // Cyan - ValueKindColor, ObjectKindColor // Bold Cyan - ValueColor, DeclNameColor // Decl kind names (VarDecl, FunctionDecl, etc) static const TerminalColor DeclKindNameColor = { raw_ostream::GREEN, true }; // Attr names (CleanupAttr, GuardedByAttr, etc) static const TerminalColor AttrColor = { raw_ostream::BLUE, true }; // Statement names (DeclStmt, ImplicitCastExpr, etc) static const TerminalColor StmtColor = { raw_ostream::MAGENTA, true }; // Comment names (FullComment, ParagraphComment, TextComment, etc) static const TerminalColor CommentColor = { raw_ostream::BLUE, false }; // Type names (int, float, etc, plus user defined types) static const TerminalColor TypeColor = { raw_ostream::GREEN, false }; // Pointer address static const TerminalColor AddressColor = { raw_ostream::YELLOW, false }; // Source locations static const TerminalColor LocationColor = { raw_ostream::YELLOW, false }; // lvalue/xvalue static const TerminalColor ValueKindColor = { raw_ostream::CYAN, false }; // bitfield/objcproperty/objcsubscript/vectorcomponent static const TerminalColor ObjectKindColor = { raw_ostream::CYAN, false }; // Null statements static const TerminalColor NullColor = { raw_ostream::BLUE, false }; // Undeserialized entities static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true }; // CastKind from CastExpr's static const TerminalColor CastColor = { raw_ostream::RED, false }; // Value of the statement static const TerminalColor ValueColor = { raw_ostream::CYAN, true }; // Decl names static const TerminalColor DeclNameColor = { raw_ostream::CYAN, true }; // Indents ( `, -. | ) static const TerminalColor IndentColor = { raw_ostream::BLUE, false }; class ASTDumper : public ConstDeclVisitor, public ConstStmtVisitor, public ConstCommentVisitor, public TypeVisitor { raw_ostream &OS; const CommandTraits *Traits; const SourceManager *SM; /// Pending[i] is an action to dump an entity at level i. llvm::SmallVector, 32> Pending; /// Indicates whether we should trigger deserialization of nodes that had /// not already been loaded. bool Deserialize = false; /// Indicates whether we're at the top level. bool TopLevel = true; /// Indicates if we're handling the first child after entering a new depth. bool FirstChild = true; /// Prefix for currently-being-dumped entity. std::string Prefix; /// Keep track of the last location we print out so that we can /// print out deltas from then on out. const char *LastLocFilename = ""; unsigned LastLocLine = ~0U; /// The \c FullComment parent of the comment being dumped. const FullComment *FC = nullptr; bool ShowColors; /// Dump a child of the current node. template void dumpChild(Fn doDumpChild) { // If we're at the top level, there's nothing interesting to do; just // run the dumper. if (TopLevel) { TopLevel = false; doDumpChild(); while (!Pending.empty()) { Pending.back()(true); Pending.pop_back(); } Prefix.clear(); OS << "\n"; TopLevel = true; return; } const FullComment *OrigFC = FC; auto dumpWithIndent = [this, doDumpChild, OrigFC](bool isLastChild) { // Print out the appropriate tree structure and work out the prefix for // children of this node. For instance: // // A Prefix = "" // |-B Prefix = "| " // | `-C Prefix = "| " // `-D Prefix = " " // |-E Prefix = " | " // `-F Prefix = " " // G Prefix = "" // // Note that the first level gets no prefix. { OS << '\n'; ColorScope Color(*this, IndentColor); OS << Prefix << (isLastChild ? '`' : '|') << '-'; this->Prefix.push_back(isLastChild ? ' ' : '|'); this->Prefix.push_back(' '); } FirstChild = true; unsigned Depth = Pending.size(); FC = OrigFC; doDumpChild(); // If any children are left, they're the last at their nesting level. // Dump those ones out now. while (Depth < Pending.size()) { Pending.back()(true); this->Pending.pop_back(); } // Restore the old prefix. this->Prefix.resize(Prefix.size() - 2); }; if (FirstChild) { Pending.push_back(std::move(dumpWithIndent)); } else { Pending.back()(false); Pending.back() = std::move(dumpWithIndent); } FirstChild = false; } class ColorScope { ASTDumper &Dumper; public: ColorScope(ASTDumper &Dumper, TerminalColor Color) : Dumper(Dumper) { if (Dumper.ShowColors) Dumper.OS.changeColor(Color.Color, Color.Bold); } ~ColorScope() { if (Dumper.ShowColors) Dumper.OS.resetColor(); } }; public: ASTDumper(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM) : OS(OS), Traits(Traits), SM(SM), ShowColors(SM && SM->getDiagnostics().getShowColors()) { } ASTDumper(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM, bool ShowColors) : OS(OS), Traits(Traits), SM(SM), ShowColors(ShowColors) {} void setDeserialize(bool D) { Deserialize = D; } void dumpDecl(const Decl *D); void dumpStmt(const Stmt *S); void dumpFullComment(const FullComment *C); // Utilities void dumpPointer(const void *Ptr); void dumpSourceRange(SourceRange R); void dumpLocation(SourceLocation Loc); void dumpBareType(QualType T, bool Desugar = true); void dumpType(QualType T); void dumpTypeAsChild(QualType T); void dumpTypeAsChild(const Type *T); void dumpBareDeclRef(const Decl *Node); void dumpDeclRef(const Decl *Node, const char *Label = nullptr); void dumpName(const NamedDecl *D); bool hasNodes(const DeclContext *DC); void dumpDeclContext(const DeclContext *DC); void dumpLookups(const DeclContext *DC, bool DumpDecls); void dumpAttr(const Attr *A); // C++ Utilities void dumpAccessSpecifier(AccessSpecifier AS); void dumpCXXCtorInitializer(const CXXCtorInitializer *Init); void dumpTemplateParameters(const TemplateParameterList *TPL); void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI); void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A); void dumpTemplateArgumentList(const TemplateArgumentList &TAL); void dumpTemplateArgument(const TemplateArgument &A, SourceRange R = SourceRange()); // Objective-C utilities. void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams); // Types void VisitComplexType(const ComplexType *T) { dumpTypeAsChild(T->getElementType()); } void VisitPointerType(const PointerType *T) { dumpTypeAsChild(T->getPointeeType()); } void VisitBlockPointerType(const BlockPointerType *T) { dumpTypeAsChild(T->getPointeeType()); } void VisitReferenceType(const ReferenceType *T) { dumpTypeAsChild(T->getPointeeType()); } void VisitRValueReferenceType(const ReferenceType *T) { if (T->isSpelledAsLValue()) OS << " written as lvalue reference"; VisitReferenceType(T); } void VisitMemberPointerType(const MemberPointerType *T) { dumpTypeAsChild(T->getClass()); dumpTypeAsChild(T->getPointeeType()); } void VisitArrayType(const ArrayType *T) { switch (T->getSizeModifier()) { case ArrayType::Normal: break; case ArrayType::Static: OS << " static"; break; case ArrayType::Star: OS << " *"; break; } OS << " " << T->getIndexTypeQualifiers().getAsString(); dumpTypeAsChild(T->getElementType()); } void VisitConstantArrayType(const ConstantArrayType *T) { OS << " " << T->getSize(); VisitArrayType(T); } void VisitVariableArrayType(const VariableArrayType *T) { OS << " "; dumpSourceRange(T->getBracketsRange()); VisitArrayType(T); dumpStmt(T->getSizeExpr()); } void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { VisitArrayType(T); OS << " "; dumpSourceRange(T->getBracketsRange()); dumpStmt(T->getSizeExpr()); } void VisitDependentSizedExtVectorType( const DependentSizedExtVectorType *T) { OS << " "; dumpLocation(T->getAttributeLoc()); dumpTypeAsChild(T->getElementType()); dumpStmt(T->getSizeExpr()); } void VisitVectorType(const VectorType *T) { switch (T->getVectorKind()) { case VectorType::GenericVector: break; case VectorType::AltiVecVector: OS << " altivec"; break; case VectorType::AltiVecPixel: OS << " altivec pixel"; break; case VectorType::AltiVecBool: OS << " altivec bool"; break; case VectorType::NeonVector: OS << " neon"; break; case VectorType::NeonPolyVector: OS << " neon poly"; break; } OS << " " << T->getNumElements(); dumpTypeAsChild(T->getElementType()); } void VisitFunctionType(const FunctionType *T) { auto EI = T->getExtInfo(); if (EI.getNoReturn()) OS << " noreturn"; if (EI.getProducesResult()) OS << " produces_result"; if (EI.getHasRegParm()) OS << " regparm " << EI.getRegParm(); OS << " " << FunctionType::getNameForCallConv(EI.getCC()); dumpTypeAsChild(T->getReturnType()); } void VisitFunctionProtoType(const FunctionProtoType *T) { auto EPI = T->getExtProtoInfo(); if (EPI.HasTrailingReturn) OS << " trailing_return"; if (T->isConst()) OS << " const"; if (T->isVolatile()) OS << " volatile"; if (T->isRestrict()) OS << " restrict"; switch (EPI.RefQualifier) { case RQ_None: break; case RQ_LValue: OS << " &"; break; case RQ_RValue: OS << " &&"; break; } // FIXME: Exception specification. // FIXME: Consumed parameters. VisitFunctionType(T); for (QualType PT : T->getParamTypes()) dumpTypeAsChild(PT); if (EPI.Variadic) dumpChild([=] { OS << "..."; }); } void VisitUnresolvedUsingType(const UnresolvedUsingType *T) { dumpDeclRef(T->getDecl()); } void VisitTypedefType(const TypedefType *T) { dumpDeclRef(T->getDecl()); } void VisitTypeOfExprType(const TypeOfExprType *T) { dumpStmt(T->getUnderlyingExpr()); } void VisitDecltypeType(const DecltypeType *T) { dumpStmt(T->getUnderlyingExpr()); } void VisitUnaryTransformType(const UnaryTransformType *T) { switch (T->getUTTKind()) { case UnaryTransformType::EnumUnderlyingType: OS << " underlying_type"; break; } dumpTypeAsChild(T->getBaseType()); } void VisitTagType(const TagType *T) { dumpDeclRef(T->getDecl()); } void VisitAttributedType(const AttributedType *T) { // FIXME: AttrKind dumpTypeAsChild(T->getModifiedType()); } void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { OS << " depth " << T->getDepth() << " index " << T->getIndex(); if (T->isParameterPack()) OS << " pack"; dumpDeclRef(T->getDecl()); } void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { dumpTypeAsChild(T->getReplacedParameter()); } void VisitSubstTemplateTypeParmPackType( const SubstTemplateTypeParmPackType *T) { dumpTypeAsChild(T->getReplacedParameter()); dumpTemplateArgument(T->getArgumentPack()); } void VisitAutoType(const AutoType *T) { if (T->isDecltypeAuto()) OS << " decltype(auto)"; if (!T->isDeduced()) OS << " undeduced"; } void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { if (T->isTypeAlias()) OS << " alias"; OS << " "; T->getTemplateName().dump(OS); for (auto &Arg : *T) dumpTemplateArgument(Arg); if (T->isTypeAlias()) dumpTypeAsChild(T->getAliasedType()); } void VisitInjectedClassNameType(const InjectedClassNameType *T) { dumpDeclRef(T->getDecl()); } void VisitObjCInterfaceType(const ObjCInterfaceType *T) { dumpDeclRef(T->getDecl()); } void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { dumpTypeAsChild(T->getPointeeType()); } void VisitAtomicType(const AtomicType *T) { dumpTypeAsChild(T->getValueType()); } void VisitPipeType(const PipeType *T) { dumpTypeAsChild(T->getElementType()); } void VisitAdjustedType(const AdjustedType *T) { dumpTypeAsChild(T->getOriginalType()); } void VisitPackExpansionType(const PackExpansionType *T) { if (auto N = T->getNumExpansions()) OS << " expansions " << *N; if (!T->isSugared()) dumpTypeAsChild(T->getPattern()); } // FIXME: ElaboratedType, DependentNameType, // DependentTemplateSpecializationType, ObjCObjectType // Decls void VisitLabelDecl(const LabelDecl *D); void VisitTypedefDecl(const TypedefDecl *D); void VisitEnumDecl(const EnumDecl *D); void VisitRecordDecl(const RecordDecl *D); void VisitEnumConstantDecl(const EnumConstantDecl *D); void VisitIndirectFieldDecl(const IndirectFieldDecl *D); void VisitFunctionDecl(const FunctionDecl *D); void VisitFieldDecl(const FieldDecl *D); void VisitVarDecl(const VarDecl *D); void VisitDecompositionDecl(const DecompositionDecl *D); void VisitBindingDecl(const BindingDecl *D); void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D); void VisitImportDecl(const ImportDecl *D); void VisitPragmaCommentDecl(const PragmaCommentDecl *D); void VisitPragmaDetectMismatchDecl(const PragmaDetectMismatchDecl *D); void VisitCapturedDecl(const CapturedDecl *D); // OpenMP decls void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D); void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D); // C++ Decls void VisitNamespaceDecl(const NamespaceDecl *D); void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D); void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D); void VisitTypeAliasDecl(const TypeAliasDecl *D); void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D); void VisitCXXRecordDecl(const CXXRecordDecl *D); void VisitStaticAssertDecl(const StaticAssertDecl *D); template void VisitTemplateDeclSpecialization(const SpecializationDecl *D, bool DumpExplicitInst, bool DumpRefOnly); template void VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst); void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); void VisitClassTemplateDecl(const ClassTemplateDecl *D); void VisitClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D); void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D); void VisitVarTemplateDecl(const VarTemplateDecl *D); void VisitVarTemplateSpecializationDecl( const VarTemplateSpecializationDecl *D); void VisitVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *D); void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); void VisitUsingDecl(const UsingDecl *D); void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); void VisitUsingShadowDecl(const UsingShadowDecl *D); void VisitConstructorUsingShadowDecl(const ConstructorUsingShadowDecl *D); void VisitLinkageSpecDecl(const LinkageSpecDecl *D); void VisitAccessSpecDecl(const AccessSpecDecl *D); void VisitFriendDecl(const FriendDecl *D); // ObjC Decls void VisitObjCIvarDecl(const ObjCIvarDecl *D); void VisitObjCMethodDecl(const ObjCMethodDecl *D); void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D); void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D); void VisitObjCImplementationDecl(const ObjCImplementationDecl *D); void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); void VisitBlockDecl(const BlockDecl *D); // Stmts. void VisitStmt(const Stmt *Node); void VisitDeclStmt(const DeclStmt *Node); void VisitAttributedStmt(const AttributedStmt *Node); void VisitLabelStmt(const LabelStmt *Node); void VisitGotoStmt(const GotoStmt *Node); void VisitCXXCatchStmt(const CXXCatchStmt *Node); void VisitCapturedStmt(const CapturedStmt *Node); // OpenMP void VisitOMPExecutableDirective(const OMPExecutableDirective *Node); // Exprs void VisitExpr(const Expr *Node); void VisitCastExpr(const CastExpr *Node); void VisitDeclRefExpr(const DeclRefExpr *Node); void VisitPredefinedExpr(const PredefinedExpr *Node); void VisitCharacterLiteral(const CharacterLiteral *Node); void VisitIntegerLiteral(const IntegerLiteral *Node); void VisitFloatingLiteral(const FloatingLiteral *Node); void VisitStringLiteral(const StringLiteral *Str); void VisitInitListExpr(const InitListExpr *ILE); void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *ILE); void VisitArrayInitIndexExpr(const ArrayInitIndexExpr *ILE); void VisitUnaryOperator(const UnaryOperator *Node); void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node); void VisitMemberExpr(const MemberExpr *Node); void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node); void VisitBinaryOperator(const BinaryOperator *Node); void VisitCompoundAssignOperator(const CompoundAssignOperator *Node); void VisitAddrLabelExpr(const AddrLabelExpr *Node); void VisitBlockExpr(const BlockExpr *Node); void VisitOpaqueValueExpr(const OpaqueValueExpr *Node); // C++ void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node); void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node); void VisitCXXThisExpr(const CXXThisExpr *Node); void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); void VisitCXXConstructExpr(const CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); void VisitCXXNewExpr(const CXXNewExpr *Node); void VisitCXXDeleteExpr(const CXXDeleteExpr *Node); void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node); void VisitExprWithCleanups(const ExprWithCleanups *Node); void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); void dumpCXXTemporary(const CXXTemporary *Temporary); void VisitLambdaExpr(const LambdaExpr *Node) { VisitExpr(Node); dumpDecl(Node->getLambdaClass()); } void VisitSizeOfPackExpr(const SizeOfPackExpr *Node); void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *Node); // ObjC void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node); void VisitObjCMessageExpr(const ObjCMessageExpr *Node); void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node); void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node); void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node); void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node); void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node); void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); // Comments. const char *getCommandName(unsigned CommandID); void dumpComment(const Comment *C); // Inline comments. void visitTextComment(const TextComment *C); void visitInlineCommandComment(const InlineCommandComment *C); void visitHTMLStartTagComment(const HTMLStartTagComment *C); void visitHTMLEndTagComment(const HTMLEndTagComment *C); // Block comments. void visitBlockCommandComment(const BlockCommandComment *C); void visitParamCommandComment(const ParamCommandComment *C); void visitTParamCommandComment(const TParamCommandComment *C); void visitVerbatimBlockComment(const VerbatimBlockComment *C); void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); void visitVerbatimLineComment(const VerbatimLineComment *C); }; } //===----------------------------------------------------------------------===// // Utilities //===----------------------------------------------------------------------===// void ASTDumper::dumpPointer(const void *Ptr) { ColorScope Color(*this, AddressColor); OS << ' ' << Ptr; } void ASTDumper::dumpLocation(SourceLocation Loc) { if (!SM) return; ColorScope Color(*this, LocationColor); SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); // The general format we print out is filename:line:col, but we drop pieces // that haven't changed since the last loc printed. PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc); if (PLoc.isInvalid()) { OS << ""; return; } if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); LastLocFilename = PLoc.getFilename(); LastLocLine = PLoc.getLine(); } else if (PLoc.getLine() != LastLocLine) { OS << "line" << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); LastLocLine = PLoc.getLine(); } else { OS << "col" << ':' << PLoc.getColumn(); } } void ASTDumper::dumpSourceRange(SourceRange R) { // Can't translate locations if a SourceManager isn't available. if (!SM) return; OS << " <"; dumpLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { OS << ", "; dumpLocation(R.getEnd()); } OS << ">"; // } void ASTDumper::dumpBareType(QualType T, bool Desugar) { ColorScope Color(*this, TypeColor); SplitQualType T_split = T.split(); OS << "'" << QualType::getAsString(T_split) << "'"; if (Desugar && !T.isNull()) { // If the type is sugared, also dump a (shallow) desugared type. SplitQualType D_split = T.getSplitDesugaredType(); if (T_split != D_split) OS << ":'" << QualType::getAsString(D_split) << "'"; } } void ASTDumper::dumpType(QualType T) { OS << ' '; dumpBareType(T); } void ASTDumper::dumpTypeAsChild(QualType T) { SplitQualType SQT = T.split(); if (!SQT.Quals.hasQualifiers()) return dumpTypeAsChild(SQT.Ty); dumpChild([=] { OS << "QualType"; dumpPointer(T.getAsOpaquePtr()); OS << " "; dumpBareType(T, false); OS << " " << T.split().Quals.getAsString(); dumpTypeAsChild(T.split().Ty); }); } void ASTDumper::dumpTypeAsChild(const Type *T) { dumpChild([=] { if (!T) { ColorScope Color(*this, NullColor); OS << "<<>>"; return; } if (const LocInfoType *LIT = llvm::dyn_cast(T)) { { ColorScope Color(*this, TypeColor); OS << "LocInfo Type"; } dumpPointer(T); dumpTypeAsChild(LIT->getTypeSourceInfo()->getType()); return; } { ColorScope Color(*this, TypeColor); OS << T->getTypeClassName() << "Type"; } dumpPointer(T); OS << " "; dumpBareType(QualType(T, 0), false); QualType SingleStepDesugar = T->getLocallyUnqualifiedSingleStepDesugaredType(); if (SingleStepDesugar != QualType(T, 0)) OS << " sugar"; if (T->isDependentType()) OS << " dependent"; else if (T->isInstantiationDependentType()) OS << " instantiation_dependent"; if (T->isVariablyModifiedType()) OS << " variably_modified"; if (T->containsUnexpandedParameterPack()) OS << " contains_unexpanded_pack"; if (T->isFromAST()) OS << " imported"; TypeVisitor::Visit(T); if (SingleStepDesugar != QualType(T, 0)) dumpTypeAsChild(SingleStepDesugar); }); } void ASTDumper::dumpBareDeclRef(const Decl *D) { if (!D) { ColorScope Color(*this, NullColor); OS << "<<>>"; return; } { ColorScope Color(*this, DeclKindNameColor); OS << D->getDeclKindName(); } dumpPointer(D); if (const NamedDecl *ND = dyn_cast(D)) { ColorScope Color(*this, DeclNameColor); OS << " '" << ND->getDeclName() << '\''; } if (const ValueDecl *VD = dyn_cast(D)) dumpType(VD->getType()); } void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) { if (!D) return; dumpChild([=]{ if (Label) OS << Label << ' '; dumpBareDeclRef(D); }); } void ASTDumper::dumpName(const NamedDecl *ND) { if (ND->getDeclName()) { ColorScope Color(*this, DeclNameColor); OS << ' ' << ND->getNameAsString(); } } bool ASTDumper::hasNodes(const DeclContext *DC) { if (!DC) return false; return DC->hasExternalLexicalStorage() || (Deserialize ? DC->decls_begin() != DC->decls_end() : DC->noload_decls_begin() != DC->noload_decls_end()); } void ASTDumper::dumpDeclContext(const DeclContext *DC) { if (!DC) return; for (auto *D : (Deserialize ? DC->decls() : DC->noload_decls())) dumpDecl(D); if (DC->hasExternalLexicalStorage()) { dumpChild([=]{ ColorScope Color(*this, UndeserializedColor); OS << ""; }); } } void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { dumpChild([=] { OS << "StoredDeclsMap "; dumpBareDeclRef(cast(DC)); const DeclContext *Primary = DC->getPrimaryContext(); if (Primary != DC) { OS << " primary"; dumpPointer(cast(Primary)); } bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); for (auto I = Deserialize ? Primary->lookups_begin() : Primary->noload_lookups_begin(), E = Deserialize ? Primary->lookups_end() : Primary->noload_lookups_end(); I != E; ++I) { DeclarationName Name = I.getLookupName(); DeclContextLookupResult R = *I; dumpChild([=] { OS << "DeclarationName "; { ColorScope Color(*this, DeclNameColor); OS << '\'' << Name << '\''; } for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); RI != RE; ++RI) { dumpChild([=] { dumpBareDeclRef(*RI); if ((*RI)->isHidden()) OS << " hidden"; // If requested, dump the redecl chain for this lookup. if (DumpDecls) { // Dump earliest decl first. std::function DumpWithPrev = [&](Decl *D) { if (Decl *Prev = D->getPreviousDecl()) DumpWithPrev(Prev); dumpDecl(D); }; DumpWithPrev(*RI); } }); } }); } if (HasUndeserializedLookups) { dumpChild([=] { ColorScope Color(*this, UndeserializedColor); OS << ""; }); } }); } void ASTDumper::dumpAttr(const Attr *A) { dumpChild([=] { { ColorScope Color(*this, AttrColor); switch (A->getKind()) { #define ATTR(X) case attr::X: OS << #X; break; #include "clang/Basic/AttrList.inc" } OS << "Attr"; } dumpPointer(A); dumpSourceRange(A->getRange()); if (A->isInherited()) OS << " Inherited"; if (A->isImplicit()) OS << " Implicit"; #include "clang/AST/AttrDump.inc" }); } static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {} template static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable *D) { const T *First = D->getFirstDecl(); if (First != D) OS << " first " << First; } template static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable *D) { const T *Prev = D->getPreviousDecl(); if (Prev) OS << " prev " << Prev; } /// Dump the previous declaration in the redeclaration chain for a declaration, /// if any. static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) { switch (D->getKind()) { #define DECL(DERIVED, BASE) \ case Decl::DERIVED: \ return dumpPreviousDeclImpl(OS, cast(D)); #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" } llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); } //===----------------------------------------------------------------------===// // C++ Utilities //===----------------------------------------------------------------------===// void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) { switch (AS) { case AS_none: break; case AS_public: OS << "public"; break; case AS_protected: OS << "protected"; break; case AS_private: OS << "private"; break; } } void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) { dumpChild([=] { OS << "CXXCtorInitializer"; if (Init->isAnyMemberInitializer()) { OS << ' '; dumpBareDeclRef(Init->getAnyMember()); } else if (Init->isBaseInitializer()) { dumpType(QualType(Init->getBaseClass(), 0)); } else if (Init->isDelegatingInitializer()) { dumpType(Init->getTypeSourceInfo()->getType()); } else { llvm_unreachable("Unknown initializer type"); } dumpStmt(Init->getInit()); }); } void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) { if (!TPL) return; for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end(); I != E; ++I) dumpDecl(*I); } void ASTDumper::dumpTemplateArgumentListInfo( const TemplateArgumentListInfo &TALI) { for (unsigned i = 0, e = TALI.size(); i < e; ++i) dumpTemplateArgumentLoc(TALI[i]); } void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) { dumpTemplateArgument(A.getArgument(), A.getSourceRange()); } void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) { for (unsigned i = 0, e = TAL.size(); i < e; ++i) dumpTemplateArgument(TAL[i]); } void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) { dumpChild([=] { OS << "TemplateArgument"; if (R.isValid()) dumpSourceRange(R); switch (A.getKind()) { case TemplateArgument::Null: OS << " null"; break; case TemplateArgument::Type: OS << " type"; dumpType(A.getAsType()); break; case TemplateArgument::Declaration: OS << " decl"; dumpDeclRef(A.getAsDecl()); break; case TemplateArgument::NullPtr: OS << " nullptr"; break; case TemplateArgument::Integral: OS << " integral " << A.getAsIntegral(); break; case TemplateArgument::Template: OS << " template "; A.getAsTemplate().dump(OS); break; case TemplateArgument::TemplateExpansion: OS << " template expansion"; A.getAsTemplateOrTemplatePattern().dump(OS); break; case TemplateArgument::Expression: OS << " expr"; dumpStmt(A.getAsExpr()); break; case TemplateArgument::Pack: OS << " pack"; for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end(); I != E; ++I) dumpTemplateArgument(*I); break; } }); } //===----------------------------------------------------------------------===// // Objective-C Utilities //===----------------------------------------------------------------------===// void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) { if (!typeParams) return; for (auto typeParam : *typeParams) { dumpDecl(typeParam); } } //===----------------------------------------------------------------------===// // Decl dumping methods. //===----------------------------------------------------------------------===// void ASTDumper::dumpDecl(const Decl *D) { dumpChild([=] { if (!D) { ColorScope Color(*this, NullColor); OS << "<<>>"; return; } { ColorScope Color(*this, DeclKindNameColor); OS << D->getDeclKindName() << "Decl"; } dumpPointer(D); if (D->getLexicalDeclContext() != D->getDeclContext()) OS << " parent " << cast(D->getDeclContext()); dumpPreviousDecl(OS, D); dumpSourceRange(D->getSourceRange()); OS << ' '; dumpLocation(D->getLocation()); - if (Module *M = D->getImportedOwningModule()) + if (D->isFromASTFile()) + OS << " imported"; + if (Module *M = D->getOwningModule()) OS << " in " << M->getFullModuleName(); - else if (Module *M = D->getLocalOwningModule()) - OS << " in (local) " << M->getFullModuleName(); if (auto *ND = dyn_cast(D)) for (Module *M : D->getASTContext().getModulesWithMergedDefinition( const_cast(ND))) dumpChild([=] { OS << "also in " << M->getFullModuleName(); }); if (const NamedDecl *ND = dyn_cast(D)) if (ND->isHidden()) OS << " hidden"; if (D->isImplicit()) OS << " implicit"; if (D->isUsed()) OS << " used"; else if (D->isThisDeclarationReferenced()) OS << " referenced"; if (D->isInvalidDecl()) OS << " invalid"; if (const FunctionDecl *FD = dyn_cast(D)) if (FD->isConstexpr()) OS << " constexpr"; ConstDeclVisitor::Visit(D); for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E; ++I) dumpAttr(*I); if (const FullComment *Comment = D->getASTContext().getLocalCommentForDeclUncached(D)) dumpFullComment(Comment); // Decls within functions are visited by the body. if (!isa(*D) && !isa(*D) && hasNodes(dyn_cast(D))) dumpDeclContext(cast(D)); }); } void ASTDumper::VisitLabelDecl(const LabelDecl *D) { dumpName(D); } void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) { dumpName(D); dumpType(D->getUnderlyingType()); if (D->isModulePrivate()) OS << " __module_private__"; dumpTypeAsChild(D->getUnderlyingType()); } void ASTDumper::VisitEnumDecl(const EnumDecl *D) { if (D->isScoped()) { if (D->isScopedUsingClassTag()) OS << " class"; else OS << " struct"; } dumpName(D); if (D->isModulePrivate()) OS << " __module_private__"; if (D->isFixed()) dumpType(D->getIntegerType()); } void ASTDumper::VisitRecordDecl(const RecordDecl *D) { OS << ' ' << D->getKindName(); dumpName(D); if (D->isModulePrivate()) OS << " __module_private__"; if (D->isCompleteDefinition()) OS << " definition"; } void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { dumpName(D); dumpType(D->getType()); if (const Expr *Init = D->getInitExpr()) dumpStmt(Init); } void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) { dumpName(D); dumpType(D->getType()); for (auto *Child : D->chain()) dumpDeclRef(Child); } void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { dumpName(D); dumpType(D->getType()); StorageClass SC = D->getStorageClass(); if (SC != SC_None) OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); if (D->isInlineSpecified()) OS << " inline"; if (D->isVirtualAsWritten()) OS << " virtual"; if (D->isModulePrivate()) OS << " __module_private__"; if (D->isPure()) OS << " pure"; if (D->isDefaulted()) { OS << " default"; if (D->isDeleted()) OS << "_delete"; } if (D->isDeletedAsWritten()) OS << " delete"; if (D->isTrivial()) OS << " trivial"; if (const FunctionProtoType *FPT = D->getType()->getAs()) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); switch (EPI.ExceptionSpec.Type) { default: break; case EST_Unevaluated: OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl; break; case EST_Uninstantiated: OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate; break; } } if (const FunctionTemplateSpecializationInfo *FTSI = D->getTemplateSpecializationInfo()) dumpTemplateArgumentList(*FTSI->TemplateArguments); if (!D->param_begin() && D->getNumParams()) dumpChild([=] { OS << "<getNumParams() << ">>"; }); else for (const ParmVarDecl *Parameter : D->parameters()) dumpDecl(Parameter); if (const CXXConstructorDecl *C = dyn_cast(D)) for (CXXConstructorDecl::init_const_iterator I = C->init_begin(), E = C->init_end(); I != E; ++I) dumpCXXCtorInitializer(*I); if (D->doesThisDeclarationHaveABody()) dumpStmt(D->getBody()); } void ASTDumper::VisitFieldDecl(const FieldDecl *D) { dumpName(D); dumpType(D->getType()); if (D->isMutable()) OS << " mutable"; if (D->isModulePrivate()) OS << " __module_private__"; if (D->isBitField()) dumpStmt(D->getBitWidth()); if (Expr *Init = D->getInClassInitializer()) dumpStmt(Init); } void ASTDumper::VisitVarDecl(const VarDecl *D) { dumpName(D); dumpType(D->getType()); StorageClass SC = D->getStorageClass(); if (SC != SC_None) OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); switch (D->getTLSKind()) { case VarDecl::TLS_None: break; case VarDecl::TLS_Static: OS << " tls"; break; case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break; } if (D->isModulePrivate()) OS << " __module_private__"; if (D->isNRVOVariable()) OS << " nrvo"; if (D->isInline()) OS << " inline"; if (D->isConstexpr()) OS << " constexpr"; if (D->hasInit()) { switch (D->getInitStyle()) { case VarDecl::CInit: OS << " cinit"; break; case VarDecl::CallInit: OS << " callinit"; break; case VarDecl::ListInit: OS << " listinit"; break; } dumpStmt(D->getInit()); } } void ASTDumper::VisitDecompositionDecl(const DecompositionDecl *D) { VisitVarDecl(D); for (auto *B : D->bindings()) dumpDecl(B); } void ASTDumper::VisitBindingDecl(const BindingDecl *D) { dumpName(D); dumpType(D->getType()); if (auto *E = D->getBinding()) dumpStmt(E); } void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { dumpStmt(D->getAsmString()); } void ASTDumper::VisitImportDecl(const ImportDecl *D) { OS << ' ' << D->getImportedModule()->getFullModuleName(); } void ASTDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) { OS << ' '; switch (D->getCommentKind()) { case PCK_Unknown: llvm_unreachable("unexpected pragma comment kind"); case PCK_Compiler: OS << "compiler"; break; case PCK_ExeStr: OS << "exestr"; break; case PCK_Lib: OS << "lib"; break; case PCK_Linker: OS << "linker"; break; case PCK_User: OS << "user"; break; } StringRef Arg = D->getArg(); if (!Arg.empty()) OS << " \"" << Arg << "\""; } void ASTDumper::VisitPragmaDetectMismatchDecl( const PragmaDetectMismatchDecl *D) { OS << " \"" << D->getName() << "\" \"" << D->getValue() << "\""; } void ASTDumper::VisitCapturedDecl(const CapturedDecl *D) { dumpStmt(D->getBody()); } //===----------------------------------------------------------------------===// // OpenMP Declarations //===----------------------------------------------------------------------===// void ASTDumper::VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { for (auto *E : D->varlists()) dumpStmt(E); } void ASTDumper::VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) { dumpName(D); dumpType(D->getType()); OS << " combiner"; dumpStmt(D->getCombiner()); if (auto *Initializer = D->getInitializer()) { OS << " initializer"; dumpStmt(Initializer); } } void ASTDumper::VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) { dumpName(D); dumpType(D->getType()); dumpStmt(D->getInit()); } //===----------------------------------------------------------------------===// // C++ Declarations //===----------------------------------------------------------------------===// void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) { dumpName(D); if (D->isInline()) OS << " inline"; if (!D->isOriginalNamespace()) dumpDeclRef(D->getOriginalNamespace(), "original"); } void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { OS << ' '; dumpBareDeclRef(D->getNominatedNamespace()); } void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { dumpName(D); dumpDeclRef(D->getAliasedNamespace()); } void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) { dumpName(D); dumpType(D->getUnderlyingType()); dumpTypeAsChild(D->getUnderlyingType()); } void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); dumpDecl(D->getTemplatedDecl()); } void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { VisitRecordDecl(D); if (!D->isCompleteDefinition()) return; for (const auto &I : D->bases()) { dumpChild([=] { if (I.isVirtual()) OS << "virtual "; dumpAccessSpecifier(I.getAccessSpecifier()); dumpType(I.getType()); if (I.isPackExpansion()) OS << "..."; }); } } void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) { dumpStmt(D->getAssertExpr()); dumpStmt(D->getMessage()); } template void ASTDumper::VisitTemplateDeclSpecialization(const SpecializationDecl *D, bool DumpExplicitInst, bool DumpRefOnly) { bool DumpedAny = false; for (auto *RedeclWithBadType : D->redecls()) { // FIXME: The redecls() range sometimes has elements of a less-specific // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives // us TagDecls, and should give CXXRecordDecls). auto *Redecl = dyn_cast(RedeclWithBadType); if (!Redecl) { // Found the injected-class-name for a class template. This will be dumped // as part of its surrounding class so we don't need to dump it here. assert(isa(RedeclWithBadType) && "expected an injected-class-name"); continue; } switch (Redecl->getTemplateSpecializationKind()) { case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: if (!DumpExplicitInst) break; // Fall through. case TSK_Undeclared: case TSK_ImplicitInstantiation: if (DumpRefOnly) dumpDeclRef(Redecl); else dumpDecl(Redecl); DumpedAny = true; break; case TSK_ExplicitSpecialization: break; } } // Ensure we dump at least one decl for each specialization. if (!DumpedAny) dumpDeclRef(D); } template void ASTDumper::VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) { dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); dumpDecl(D->getTemplatedDecl()); for (auto *Child : D->specializations()) VisitTemplateDeclSpecialization(Child, DumpExplicitInst, !D->isCanonicalDecl()); } void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { // FIXME: We don't add a declaration of a function template specialization // to its context when it's explicitly instantiated, so dump explicit // instantiations when we dump the template itself. VisitTemplateDecl(D, true); } void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { VisitTemplateDecl(D, false); } void ASTDumper::VisitClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *D) { VisitCXXRecordDecl(D); dumpTemplateArgumentList(D->getTemplateArgs()); } void ASTDumper::VisitClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *D) { VisitClassTemplateSpecializationDecl(D); dumpTemplateParameters(D->getTemplateParameters()); } void ASTDumper::VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D) { dumpDeclRef(D->getSpecialization()); if (D->hasExplicitTemplateArgs()) dumpTemplateArgumentListInfo(D->templateArgs()); } void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { VisitTemplateDecl(D, false); } void ASTDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); } void ASTDumper::VisitVarTemplateSpecializationDecl( const VarTemplateSpecializationDecl *D) { dumpTemplateArgumentList(D->getTemplateArgs()); VisitVarDecl(D); } void ASTDumper::VisitVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *D) { dumpTemplateParameters(D->getTemplateParameters()); VisitVarTemplateSpecializationDecl(D); } void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { if (D->wasDeclaredWithTypename()) OS << " typename"; else OS << " class"; OS << " depth " << D->getDepth() << " index " << D->getIndex(); if (D->isParameterPack()) OS << " ..."; dumpName(D); if (D->hasDefaultArgument()) dumpTemplateArgument(D->getDefaultArgument()); } void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { dumpType(D->getType()); OS << " depth " << D->getDepth() << " index " << D->getIndex(); if (D->isParameterPack()) OS << " ..."; dumpName(D); if (D->hasDefaultArgument()) dumpTemplateArgument(D->getDefaultArgument()); } void ASTDumper::VisitTemplateTemplateParmDecl( const TemplateTemplateParmDecl *D) { OS << " depth " << D->getDepth() << " index " << D->getIndex(); if (D->isParameterPack()) OS << " ..."; dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); if (D->hasDefaultArgument()) dumpTemplateArgumentLoc(D->getDefaultArgument()); } void ASTDumper::VisitUsingDecl(const UsingDecl *D) { OS << ' '; if (D->getQualifier()) D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getNameAsString(); } void ASTDumper::VisitUnresolvedUsingTypenameDecl( const UnresolvedUsingTypenameDecl *D) { OS << ' '; if (D->getQualifier()) D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getNameAsString(); } void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { OS << ' '; if (D->getQualifier()) D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getNameAsString(); dumpType(D->getType()); } void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) { OS << ' '; dumpBareDeclRef(D->getTargetDecl()); if (auto *TD = dyn_cast(D->getUnderlyingDecl())) dumpTypeAsChild(TD->getTypeForDecl()); } void ASTDumper::VisitConstructorUsingShadowDecl( const ConstructorUsingShadowDecl *D) { if (D->constructsVirtualBase()) OS << " virtual"; dumpChild([=] { OS << "target "; dumpBareDeclRef(D->getTargetDecl()); }); dumpChild([=] { OS << "nominated "; dumpBareDeclRef(D->getNominatedBaseClass()); OS << ' '; dumpBareDeclRef(D->getNominatedBaseClassShadowDecl()); }); dumpChild([=] { OS << "constructed "; dumpBareDeclRef(D->getConstructedBaseClass()); OS << ' '; dumpBareDeclRef(D->getConstructedBaseClassShadowDecl()); }); } void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { switch (D->getLanguage()) { case LinkageSpecDecl::lang_c: OS << " C"; break; case LinkageSpecDecl::lang_cxx: OS << " C++"; break; } } void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) { OS << ' '; dumpAccessSpecifier(D->getAccess()); } void ASTDumper::VisitFriendDecl(const FriendDecl *D) { if (TypeSourceInfo *T = D->getFriendType()) dumpType(T->getType()); else dumpDecl(D->getFriendDecl()); } //===----------------------------------------------------------------------===// // Obj-C Declarations //===----------------------------------------------------------------------===// void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { dumpName(D); dumpType(D->getType()); if (D->getSynthesize()) OS << " synthesize"; switch (D->getAccessControl()) { case ObjCIvarDecl::None: OS << " none"; break; case ObjCIvarDecl::Private: OS << " private"; break; case ObjCIvarDecl::Protected: OS << " protected"; break; case ObjCIvarDecl::Public: OS << " public"; break; case ObjCIvarDecl::Package: OS << " package"; break; } } void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { if (D->isInstanceMethod()) OS << " -"; else OS << " +"; dumpName(D); dumpType(D->getReturnType()); if (D->isThisDeclarationADefinition()) { dumpDeclContext(D); } else { for (const ParmVarDecl *Parameter : D->parameters()) dumpDecl(Parameter); } if (D->isVariadic()) dumpChild([=] { OS << "..."; }); if (D->hasBody()) dumpStmt(D->getBody()); } void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) { dumpName(D); switch (D->getVariance()) { case ObjCTypeParamVariance::Invariant: break; case ObjCTypeParamVariance::Covariant: OS << " covariant"; break; case ObjCTypeParamVariance::Contravariant: OS << " contravariant"; break; } if (D->hasExplicitBound()) OS << " bounded"; dumpType(D->getUnderlyingType()); } void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); dumpObjCTypeParamList(D->getTypeParamList()); dumpDeclRef(D->getImplementation()); for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) dumpDeclRef(*I); } void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); dumpDeclRef(D->getCategoryDecl()); } void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { dumpName(D); for (auto *Child : D->protocols()) dumpDeclRef(Child); } void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { dumpName(D); dumpObjCTypeParamList(D->getTypeParamListAsWritten()); dumpDeclRef(D->getSuperClass(), "super"); dumpDeclRef(D->getImplementation()); for (auto *Child : D->protocols()) dumpDeclRef(Child); } void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { dumpName(D); dumpDeclRef(D->getSuperClass(), "super"); dumpDeclRef(D->getClassInterface()); for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(), E = D->init_end(); I != E; ++I) dumpCXXCtorInitializer(*I); } void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); } void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { dumpName(D); dumpType(D->getType()); if (D->getPropertyImplementation() == ObjCPropertyDecl::Required) OS << " required"; else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional) OS << " optional"; ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes(); if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) { if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly) OS << " readonly"; if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) OS << " assign"; if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite) OS << " readwrite"; if (Attrs & ObjCPropertyDecl::OBJC_PR_retain) OS << " retain"; if (Attrs & ObjCPropertyDecl::OBJC_PR_copy) OS << " copy"; if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) OS << " nonatomic"; if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic) OS << " atomic"; if (Attrs & ObjCPropertyDecl::OBJC_PR_weak) OS << " weak"; if (Attrs & ObjCPropertyDecl::OBJC_PR_strong) OS << " strong"; if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) OS << " unsafe_unretained"; if (Attrs & ObjCPropertyDecl::OBJC_PR_class) OS << " class"; if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) dumpDeclRef(D->getGetterMethodDecl(), "getter"); if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) dumpDeclRef(D->getSetterMethodDecl(), "setter"); } } void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { dumpName(D->getPropertyDecl()); if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) OS << " synthesize"; else OS << " dynamic"; dumpDeclRef(D->getPropertyDecl()); dumpDeclRef(D->getPropertyIvarDecl()); } void ASTDumper::VisitBlockDecl(const BlockDecl *D) { for (auto I : D->parameters()) dumpDecl(I); if (D->isVariadic()) dumpChild([=]{ OS << "..."; }); if (D->capturesCXXThis()) dumpChild([=]{ OS << "capture this"; }); for (const auto &I : D->captures()) { dumpChild([=] { OS << "capture"; if (I.isByRef()) OS << " byref"; if (I.isNested()) OS << " nested"; if (I.getVariable()) { OS << ' '; dumpBareDeclRef(I.getVariable()); } if (I.hasCopyExpr()) dumpStmt(I.getCopyExpr()); }); } dumpStmt(D->getBody()); } //===----------------------------------------------------------------------===// // Stmt dumping methods. //===----------------------------------------------------------------------===// void ASTDumper::dumpStmt(const Stmt *S) { dumpChild([=] { if (!S) { ColorScope Color(*this, NullColor); OS << "<<>>"; return; } if (const DeclStmt *DS = dyn_cast(S)) { VisitDeclStmt(DS); return; } ConstStmtVisitor::Visit(S); for (const Stmt *SubStmt : S->children()) dumpStmt(SubStmt); }); } void ASTDumper::VisitStmt(const Stmt *Node) { { ColorScope Color(*this, StmtColor); OS << Node->getStmtClassName(); } dumpPointer(Node); dumpSourceRange(Node->getSourceRange()); } void ASTDumper::VisitDeclStmt(const DeclStmt *Node) { VisitStmt(Node); for (DeclStmt::const_decl_iterator I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) dumpDecl(*I); } void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) { VisitStmt(Node); for (ArrayRef::iterator I = Node->getAttrs().begin(), E = Node->getAttrs().end(); I != E; ++I) dumpAttr(*I); } void ASTDumper::VisitLabelStmt(const LabelStmt *Node) { VisitStmt(Node); OS << " '" << Node->getName() << "'"; } void ASTDumper::VisitGotoStmt(const GotoStmt *Node) { VisitStmt(Node); OS << " '" << Node->getLabel()->getName() << "'"; dumpPointer(Node->getLabel()); } void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) { VisitStmt(Node); dumpDecl(Node->getExceptionDecl()); } void ASTDumper::VisitCapturedStmt(const CapturedStmt *Node) { VisitStmt(Node); dumpDecl(Node->getCapturedDecl()); } //===----------------------------------------------------------------------===// // OpenMP dumping methods. //===----------------------------------------------------------------------===// void ASTDumper::VisitOMPExecutableDirective( const OMPExecutableDirective *Node) { VisitStmt(Node); for (auto *C : Node->clauses()) { dumpChild([=] { if (!C) { ColorScope Color(*this, NullColor); OS << "<<>> OMPClause"; return; } { ColorScope Color(*this, AttrColor); StringRef ClauseName(getOpenMPClauseName(C->getClauseKind())); OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper() << ClauseName.drop_front() << "Clause"; } dumpPointer(C); dumpSourceRange(SourceRange(C->getLocStart(), C->getLocEnd())); if (C->isImplicit()) OS << " "; for (auto *S : C->children()) dumpStmt(S); }); } } //===----------------------------------------------------------------------===// // Expr dumping methods. //===----------------------------------------------------------------------===// void ASTDumper::VisitExpr(const Expr *Node) { VisitStmt(Node); dumpType(Node->getType()); { ColorScope Color(*this, ValueKindColor); switch (Node->getValueKind()) { case VK_RValue: break; case VK_LValue: OS << " lvalue"; break; case VK_XValue: OS << " xvalue"; break; } } { ColorScope Color(*this, ObjectKindColor); switch (Node->getObjectKind()) { case OK_Ordinary: break; case OK_BitField: OS << " bitfield"; break; case OK_ObjCProperty: OS << " objcproperty"; break; case OK_ObjCSubscript: OS << " objcsubscript"; break; case OK_VectorComponent: OS << " vectorcomponent"; break; } } } static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) { if (Node->path_empty()) return; OS << " ("; bool First = true; for (CastExpr::path_const_iterator I = Node->path_begin(), E = Node->path_end(); I != E; ++I) { const CXXBaseSpecifier *Base = *I; if (!First) OS << " -> "; const CXXRecordDecl *RD = cast(Base->getType()->getAs()->getDecl()); if (Base->isVirtual()) OS << "virtual "; OS << RD->getName(); First = false; } OS << ')'; } void ASTDumper::VisitCastExpr(const CastExpr *Node) { VisitExpr(Node); OS << " <"; { ColorScope Color(*this, CastColor); OS << Node->getCastKindName(); } dumpBasePath(OS, Node); OS << ">"; } void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) { VisitExpr(Node); OS << " "; dumpBareDeclRef(Node->getDecl()); if (Node->getDecl() != Node->getFoundDecl()) { OS << " ("; dumpBareDeclRef(Node->getFoundDecl()); OS << ")"; } } void ASTDumper::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node) { VisitExpr(Node); OS << " ("; if (!Node->requiresADL()) OS << "no "; OS << "ADL) = '" << Node->getName() << '\''; UnresolvedLookupExpr::decls_iterator I = Node->decls_begin(), E = Node->decls_end(); if (I == E) OS << " empty"; for (; I != E; ++I) dumpPointer(*I); } void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) { VisitExpr(Node); { ColorScope Color(*this, DeclKindNameColor); OS << " " << Node->getDecl()->getDeclKindName() << "Decl"; } OS << "='" << *Node->getDecl() << "'"; dumpPointer(Node->getDecl()); if (Node->isFreeIvar()) OS << " isFreeIvar"; } void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) { VisitExpr(Node); OS << " " << PredefinedExpr::getIdentTypeName(Node->getIdentType()); } void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) { VisitExpr(Node); ColorScope Color(*this, ValueColor); OS << " " << Node->getValue(); } void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) { VisitExpr(Node); bool isSigned = Node->getType()->isSignedIntegerType(); ColorScope Color(*this, ValueColor); OS << " " << Node->getValue().toString(10, isSigned); } void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) { VisitExpr(Node); ColorScope Color(*this, ValueColor); OS << " " << Node->getValueAsApproximateDouble(); } void ASTDumper::VisitStringLiteral(const StringLiteral *Str) { VisitExpr(Str); ColorScope Color(*this, ValueColor); OS << " "; Str->outputString(OS); } void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) { VisitExpr(ILE); if (auto *Filler = ILE->getArrayFiller()) { dumpChild([=] { OS << "array filler"; dumpStmt(Filler); }); } if (auto *Field = ILE->getInitializedFieldInUnion()) { OS << " field "; dumpBareDeclRef(Field); } } void ASTDumper::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { VisitExpr(E); } void ASTDumper::VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E) { VisitExpr(E); } void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) { VisitExpr(Node); OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } void ASTDumper::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *Node) { VisitExpr(Node); switch(Node->getKind()) { case UETT_SizeOf: OS << " sizeof"; break; case UETT_AlignOf: OS << " alignof"; break; case UETT_VecStep: OS << " vec_step"; break; case UETT_OpenMPRequiredSimdAlign: OS << " __builtin_omp_required_simd_align"; break; } if (Node->isArgumentType()) dumpType(Node->getArgumentType()); } void ASTDumper::VisitMemberExpr(const MemberExpr *Node) { VisitExpr(Node); OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl(); dumpPointer(Node->getMemberDecl()); } void ASTDumper::VisitExtVectorElementExpr(const ExtVectorElementExpr *Node) { VisitExpr(Node); OS << " " << Node->getAccessor().getNameStart(); } void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) { VisitExpr(Node); OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } void ASTDumper::VisitCompoundAssignOperator( const CompoundAssignOperator *Node) { VisitExpr(Node); OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "' ComputeLHSTy="; dumpBareType(Node->getComputationLHSType()); OS << " ComputeResultTy="; dumpBareType(Node->getComputationResultType()); } void ASTDumper::VisitBlockExpr(const BlockExpr *Node) { VisitExpr(Node); dumpDecl(Node->getBlockDecl()); } void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { VisitExpr(Node); if (Expr *Source = Node->getSourceExpr()) dumpStmt(Source); } // GNU extensions. void ASTDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) { VisitExpr(Node); OS << " " << Node->getLabel()->getName(); dumpPointer(Node->getLabel()); } //===----------------------------------------------------------------------===// // C++ Expressions //===----------------------------------------------------------------------===// void ASTDumper::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) { VisitExpr(Node); OS << " " << Node->getCastName() << "<" << Node->getTypeAsWritten().getAsString() << ">" << " <" << Node->getCastKindName(); dumpBasePath(OS, Node); OS << ">"; } void ASTDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) { VisitExpr(Node); OS << " " << (Node->getValue() ? "true" : "false"); } void ASTDumper::VisitCXXThisExpr(const CXXThisExpr *Node) { VisitExpr(Node); OS << " this"; } void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) { VisitExpr(Node); OS << " functional cast to " << Node->getTypeAsWritten().getAsString() << " <" << Node->getCastKindName() << ">"; } void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) { VisitExpr(Node); CXXConstructorDecl *Ctor = Node->getConstructor(); dumpType(Ctor->getType()); if (Node->isElidable()) OS << " elidable"; if (Node->requiresZeroInitialization()) OS << " zeroing"; } void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) { VisitExpr(Node); OS << " "; dumpCXXTemporary(Node->getTemporary()); } void ASTDumper::VisitCXXNewExpr(const CXXNewExpr *Node) { VisitExpr(Node); if (Node->isGlobalNew()) OS << " global"; if (Node->isArray()) OS << " array"; if (Node->getOperatorNew()) { OS << ' '; dumpBareDeclRef(Node->getOperatorNew()); } // We could dump the deallocation function used in case of error, but it's // usually not that interesting. } void ASTDumper::VisitCXXDeleteExpr(const CXXDeleteExpr *Node) { VisitExpr(Node); if (Node->isGlobalDelete()) OS << " global"; if (Node->isArrayForm()) OS << " array"; if (Node->getOperatorDelete()) { OS << ' '; dumpBareDeclRef(Node->getOperatorDelete()); } } void ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) { VisitExpr(Node); if (const ValueDecl *VD = Node->getExtendingDecl()) { OS << " extended by "; dumpBareDeclRef(VD); } } void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) { VisitExpr(Node); for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) dumpDeclRef(Node->getObject(i), "cleanup"); } void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) { OS << "(CXXTemporary"; dumpPointer(Temporary); OS << ")"; } void ASTDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) { VisitExpr(Node); dumpPointer(Node->getPack()); dumpName(Node->getPack()); if (Node->isPartiallySubstituted()) for (const auto &A : Node->getPartialArguments()) dumpTemplateArgument(A); } void ASTDumper::VisitCXXDependentScopeMemberExpr( const CXXDependentScopeMemberExpr *Node) { VisitExpr(Node); OS << " " << (Node->isArrow() ? "->" : ".") << Node->getMember(); } //===----------------------------------------------------------------------===// // Obj-C Expressions //===----------------------------------------------------------------------===// void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) { VisitExpr(Node); OS << " selector="; Node->getSelector().print(OS); switch (Node->getReceiverKind()) { case ObjCMessageExpr::Instance: break; case ObjCMessageExpr::Class: OS << " class="; dumpBareType(Node->getClassReceiver()); break; case ObjCMessageExpr::SuperInstance: OS << " super (instance)"; break; case ObjCMessageExpr::SuperClass: OS << " super (class)"; break; } } void ASTDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) { VisitExpr(Node); if (auto *BoxingMethod = Node->getBoxingMethod()) { OS << " selector="; BoxingMethod->getSelector().print(OS); } } void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) { VisitStmt(Node); if (const VarDecl *CatchParam = Node->getCatchParamDecl()) dumpDecl(CatchParam); else OS << " catch all"; } void ASTDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) { VisitExpr(Node); dumpType(Node->getEncodedType()); } void ASTDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) { VisitExpr(Node); OS << " "; Node->getSelector().print(OS); } void ASTDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) { VisitExpr(Node); OS << ' ' << *Node->getProtocol(); } void ASTDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) { VisitExpr(Node); if (Node->isImplicitProperty()) { OS << " Kind=MethodRef Getter=\""; if (Node->getImplicitPropertyGetter()) Node->getImplicitPropertyGetter()->getSelector().print(OS); else OS << "(null)"; OS << "\" Setter=\""; if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter()) Setter->getSelector().print(OS); else OS << "(null)"; OS << "\""; } else { OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"'; } if (Node->isSuperReceiver()) OS << " super"; OS << " Messaging="; if (Node->isMessagingGetter() && Node->isMessagingSetter()) OS << "Getter&Setter"; else if (Node->isMessagingGetter()) OS << "Getter"; else if (Node->isMessagingSetter()) OS << "Setter"; } void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) { VisitExpr(Node); if (Node->isArraySubscriptRefExpr()) OS << " Kind=ArraySubscript GetterForArray=\""; else OS << " Kind=DictionarySubscript GetterForDictionary=\""; if (Node->getAtIndexMethodDecl()) Node->getAtIndexMethodDecl()->getSelector().print(OS); else OS << "(null)"; if (Node->isArraySubscriptRefExpr()) OS << "\" SetterForArray=\""; else OS << "\" SetterForDictionary=\""; if (Node->setAtIndexMethodDecl()) Node->setAtIndexMethodDecl()->getSelector().print(OS); else OS << "(null)"; } void ASTDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) { VisitExpr(Node); OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no"); } //===----------------------------------------------------------------------===// // Comments //===----------------------------------------------------------------------===// const char *ASTDumper::getCommandName(unsigned CommandID) { if (Traits) return Traits->getCommandInfo(CommandID)->Name; const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); if (Info) return Info->Name; return ""; } void ASTDumper::dumpFullComment(const FullComment *C) { if (!C) return; FC = C; dumpComment(C); FC = nullptr; } void ASTDumper::dumpComment(const Comment *C) { dumpChild([=] { if (!C) { ColorScope Color(*this, NullColor); OS << "<<>>"; return; } { ColorScope Color(*this, CommentColor); OS << C->getCommentKindName(); } dumpPointer(C); dumpSourceRange(C->getSourceRange()); ConstCommentVisitor::visit(C); for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); I != E; ++I) dumpComment(*I); }); } void ASTDumper::visitTextComment(const TextComment *C) { OS << " Text=\"" << C->getText() << "\""; } void ASTDumper::visitInlineCommandComment(const InlineCommandComment *C) { OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; switch (C->getRenderKind()) { case InlineCommandComment::RenderNormal: OS << " RenderNormal"; break; case InlineCommandComment::RenderBold: OS << " RenderBold"; break; case InlineCommandComment::RenderMonospaced: OS << " RenderMonospaced"; break; case InlineCommandComment::RenderEmphasized: OS << " RenderEmphasized"; break; } for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; } void ASTDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) { OS << " Name=\"" << C->getTagName() << "\""; if (C->getNumAttrs() != 0) { OS << " Attrs: "; for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) { const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\""; } } if (C->isSelfClosing()) OS << " SelfClosing"; } void ASTDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) { OS << " Name=\"" << C->getTagName() << "\""; } void ASTDumper::visitBlockCommandComment(const BlockCommandComment *C) { OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; } void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) { OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection()); if (C->isDirectionExplicit()) OS << " explicitly"; else OS << " implicitly"; if (C->hasParamName()) { if (C->isParamIndexValid()) OS << " Param=\"" << C->getParamName(FC) << "\""; else OS << " Param=\"" << C->getParamNameAsWritten() << "\""; } if (C->isParamIndexValid() && !C->isVarArgParam()) OS << " ParamIndex=" << C->getParamIndex(); } void ASTDumper::visitTParamCommandComment(const TParamCommandComment *C) { if (C->hasParamName()) { if (C->isPositionValid()) OS << " Param=\"" << C->getParamName(FC) << "\""; else OS << " Param=\"" << C->getParamNameAsWritten() << "\""; } if (C->isPositionValid()) { OS << " Position=<"; for (unsigned i = 0, e = C->getDepth(); i != e; ++i) { OS << C->getIndex(i); if (i != e - 1) OS << ", "; } OS << ">"; } } void ASTDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) { OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"" " CloseName=\"" << C->getCloseName() << "\""; } void ASTDumper::visitVerbatimBlockLineComment( const VerbatimBlockLineComment *C) { OS << " Text=\"" << C->getText() << "\""; } void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) { OS << " Text=\"" << C->getText() << "\""; } //===----------------------------------------------------------------------===// // Type method implementations //===----------------------------------------------------------------------===// void QualType::dump(const char *msg) const { if (msg) llvm::errs() << msg << ": "; dump(); } LLVM_DUMP_METHOD void QualType::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS) const { ASTDumper Dumper(OS, nullptr, nullptr); Dumper.dumpTypeAsChild(*this); } LLVM_DUMP_METHOD void Type::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const { QualType(this, 0).dump(OS); } //===----------------------------------------------------------------------===// // Decl method implementations //===----------------------------------------------------------------------===// LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const { ASTDumper P(OS, &getASTContext().getCommentCommandTraits(), &getASTContext().getSourceManager()); P.setDeserialize(Deserialize); P.dumpDecl(this); } LLVM_DUMP_METHOD void Decl::dumpColor() const { ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(), &getASTContext().getSourceManager(), /*ShowColors*/true); P.dumpDecl(this); } LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { dumpLookups(llvm::errs()); } LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS, bool DumpDecls, bool Deserialize) const { const DeclContext *DC = this; while (!DC->isTranslationUnit()) DC = DC->getParent(); ASTContext &Ctx = cast(DC)->getASTContext(); ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager()); P.setDeserialize(Deserialize); P.dumpLookups(this, DumpDecls); } //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const { dump(llvm::errs(), SM); } LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { ASTDumper P(OS, nullptr, &SM); P.dumpStmt(this); } LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const { ASTDumper P(OS, nullptr, nullptr); P.dumpStmt(this); } LLVM_DUMP_METHOD void Stmt::dump() const { ASTDumper P(llvm::errs(), nullptr, nullptr); P.dumpStmt(this); } LLVM_DUMP_METHOD void Stmt::dumpColor() const { ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); P.dumpStmt(this); } //===----------------------------------------------------------------------===// // Comment method implementations //===----------------------------------------------------------------------===// LLVM_DUMP_METHOD void Comment::dump() const { dump(llvm::errs(), nullptr, nullptr); } LLVM_DUMP_METHOD void Comment::dump(const ASTContext &Context) const { dump(llvm::errs(), &Context.getCommentCommandTraits(), &Context.getSourceManager()); } void Comment::dump(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM) const { const FullComment *FC = dyn_cast(this); ASTDumper D(OS, Traits, SM); D.dumpFullComment(FC); } LLVM_DUMP_METHOD void Comment::dumpColor() const { const FullComment *FC = dyn_cast(this); ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); D.dumpFullComment(FC); } Index: vendor/clang/dist/lib/AST/Decl.cpp =================================================================== --- vendor/clang/dist/lib/AST/Decl.cpp (revision 318415) +++ vendor/clang/dist/lib/AST/Decl.cpp (revision 318416) @@ -1,4416 +1,4414 @@ //===--- Decl.cpp - Declaration AST Node Implementation -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Decl subclasses. // //===----------------------------------------------------------------------===// #include "clang/AST/Decl.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Stmt.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Module.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Support/ErrorHandling.h" #include using namespace clang; Decl *clang::getPrimaryMergedDecl(Decl *D) { return D->getASTContext().getPrimaryMergedDecl(D); } // Defined here so that it can be inlined into its direct callers. bool Decl::isOutOfLine() const { return !getLexicalDeclContext()->Equals(getDeclContext()); } TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx) : Decl(TranslationUnit, nullptr, SourceLocation()), - DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) { - Hidden = Ctx.getLangOpts().ModulesLocalVisibility; -} + DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {} //===----------------------------------------------------------------------===// // NamedDecl Implementation //===----------------------------------------------------------------------===// // Visibility rules aren't rigorously externally specified, but here // are the basic principles behind what we implement: // // 1. An explicit visibility attribute is generally a direct expression // of the user's intent and should be honored. Only the innermost // visibility attribute applies. If no visibility attribute applies, // global visibility settings are considered. // // 2. There is one caveat to the above: on or in a template pattern, // an explicit visibility attribute is just a default rule, and // visibility can be decreased by the visibility of template // arguments. But this, too, has an exception: an attribute on an // explicit specialization or instantiation causes all the visibility // restrictions of the template arguments to be ignored. // // 3. A variable that does not otherwise have explicit visibility can // be restricted by the visibility of its type. // // 4. A visibility restriction is explicit if it comes from an // attribute (or something like it), not a global visibility setting. // When emitting a reference to an external symbol, visibility // restrictions are ignored unless they are explicit. // // 5. When computing the visibility of a non-type, including a // non-type member of a class, only non-type visibility restrictions // are considered: the 'visibility' attribute, global value-visibility // settings, and a few special cases like __private_extern. // // 6. When computing the visibility of a type, including a type member // of a class, only type visibility restrictions are considered: // the 'type_visibility' attribute and global type-visibility settings. // However, a 'visibility' attribute counts as a 'type_visibility' // attribute on any declaration that only has the former. // // The visibility of a "secondary" entity, like a template argument, // is computed using the kind of that entity, not the kind of the // primary entity for which we are computing visibility. For example, // the visibility of a specialization of either of these templates: // template bool has_match(list, X); // template class matcher; // is restricted according to the type visibility of the argument 'T', // the type visibility of 'bool(&)(T,X)', and the value visibility of // the argument function 'compare'. That 'has_match' is a value // and 'matcher' is a type only matters when looking for attributes // and settings from the immediate context. const unsigned IgnoreExplicitVisibilityBit = 2; const unsigned IgnoreAllVisibilityBit = 4; /// Kinds of LV computation. The linkage side of the computation is /// always the same, but different things can change how visibility is /// computed. enum LVComputationKind { /// Do an LV computation for, ultimately, a type. /// Visibility may be restricted by type visibility settings and /// the visibility of template arguments. LVForType = NamedDecl::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. LVForValue = NamedDecl::VisibilityForValue, /// Do an LV computation for, ultimately, a type that already has /// some sort of explicit visibility. Visibility may only be /// restricted by the visibility of template arguments. LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit), /// Do an LV computation for, ultimately, a non-type declaration /// that already has some sort of explicit visibility. Visibility /// may only be restricted by the visibility of template arguments. LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit), /// Do an LV computation when we only care about the linkage. LVForLinkageOnly = LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit }; /// Does this computation kind permit us to consider additional /// visibility settings from attributes and the like? static bool hasExplicitVisibilityAlready(LVComputationKind computation) { return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0); } /// Given an LVComputationKind, return one of the same type/value sort /// that records that it already has explicit visibility. static LVComputationKind withExplicitVisibilityAlready(LVComputationKind oldKind) { LVComputationKind newKind = static_cast(unsigned(oldKind) | IgnoreExplicitVisibilityBit); assert(oldKind != LVForType || newKind == LVForExplicitType); assert(oldKind != LVForValue || newKind == LVForExplicitValue); assert(oldKind != LVForExplicitType || newKind == LVForExplicitType); assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue); return newKind; } static Optional getExplicitVisibility(const NamedDecl *D, LVComputationKind kind) { assert(!hasExplicitVisibilityAlready(kind) && "asking for explicit visibility when we shouldn't be"); return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind); } /// Is the given declaration a "type" or a "value" for the purposes of /// visibility computation? static bool usesTypeVisibility(const NamedDecl *D) { return isa(D) || isa(D) || isa(D); } /// Does the given declaration have member specialization information, /// and if so, is it an explicit specialization? template static typename std::enable_if::value, bool>::type isExplicitMemberSpecialization(const T *D) { if (const MemberSpecializationInfo *member = D->getMemberSpecializationInfo()) { return member->isExplicitSpecialization(); } return false; } /// For templates, this question is easier: a member template can't be /// explicitly instantiated, so there's a single bit indicating whether /// or not this is an explicit member specialization. static bool isExplicitMemberSpecialization(const RedeclarableTemplateDecl *D) { return D->isMemberSpecialization(); } /// Given a visibility attribute, return the explicit visibility /// associated with it. template static Visibility getVisibilityFromAttr(const T *attr) { switch (attr->getVisibility()) { case T::Default: return DefaultVisibility; case T::Hidden: return HiddenVisibility; case T::Protected: return ProtectedVisibility; } llvm_unreachable("bad visibility kind"); } /// Return the explicit visibility of the given declaration. static Optional getVisibilityOf(const NamedDecl *D, NamedDecl::ExplicitVisibilityKind kind) { // If we're ultimately computing the visibility of a type, look for // a 'type_visibility' attribute before looking for 'visibility'. if (kind == NamedDecl::VisibilityForType) { if (const auto *A = D->getAttr()) { return getVisibilityFromAttr(A); } } // If this declaration has an explicit visibility attribute, use it. if (const auto *A = D->getAttr()) { return getVisibilityFromAttr(A); } // If we're on Mac OS X, an 'availability' for Mac OS X attribute // implies visibility(default). if (D->getASTContext().getTargetInfo().getTriple().isOSDarwin()) { for (const auto *A : D->specific_attrs()) if (A->getPlatform()->getName().equals("macos")) return DefaultVisibility; } return None; } static LinkageInfo getLVForType(const Type &T, LVComputationKind computation) { if (computation == LVForLinkageOnly) return LinkageInfo(T.getLinkage(), DefaultVisibility, true); return T.getLinkageAndVisibility(); } /// \brief Get the most restrictive linkage for the types in the given /// template parameter list. For visibility purposes, template /// parameters are part of the signature of a template. static LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params, LVComputationKind computation) { LinkageInfo LV; for (const NamedDecl *P : *Params) { // Template type parameters are the most common and never // contribute to visibility, pack or not. if (isa(P)) continue; // Non-type template parameters can be restricted by the value type, e.g. // template class A { ... }; // We have to be careful here, though, because we can be dealing with // dependent types. if (const auto *NTTP = dyn_cast(P)) { // Handle the non-pack case first. if (!NTTP->isExpandedParameterPack()) { if (!NTTP->getType()->isDependentType()) { LV.merge(getLVForType(*NTTP->getType(), computation)); } continue; } // Look at all the types in an expanded pack. for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) { QualType type = NTTP->getExpansionType(i); if (!type->isDependentType()) LV.merge(type->getLinkageAndVisibility()); } continue; } // Template template parameters can be restricted by their // template parameters, recursively. const auto *TTP = cast(P); // Handle the non-pack case first. if (!TTP->isExpandedParameterPack()) { LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters(), computation)); continue; } // Look at all expansions in an expanded pack. for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters(); i != n; ++i) { LV.merge(getLVForTemplateParameterList( TTP->getExpansionTemplateParameters(i), computation)); } } return LV; } /// getLVForDecl - Get the linkage and visibility for the given declaration. static LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation); static const Decl *getOutermostFuncOrBlockContext(const Decl *D) { const Decl *Ret = nullptr; const DeclContext *DC = D->getDeclContext(); while (DC->getDeclKind() != Decl::TranslationUnit) { if (isa(DC) || isa(DC)) Ret = cast(DC); DC = DC->getParent(); } return Ret; } /// \brief Get the most restrictive linkage for the types and /// declarations in the given template argument list. /// /// Note that we don't take an LVComputationKind because we always /// want to honor the visibility of template arguments in the same way. static LinkageInfo getLVForTemplateArgumentList(ArrayRef Args, LVComputationKind computation) { LinkageInfo LV; for (const TemplateArgument &Arg : Args) { switch (Arg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Expression: continue; case TemplateArgument::Type: LV.merge(getLVForType(*Arg.getAsType(), computation)); continue; case TemplateArgument::Declaration: if (const auto *ND = dyn_cast(Arg.getAsDecl())) { assert(!usesTypeVisibility(ND)); LV.merge(getLVForDecl(ND, computation)); } continue; case TemplateArgument::NullPtr: LV.merge(Arg.getNullPtrType()->getLinkageAndVisibility()); continue; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: if (TemplateDecl *Template = Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl()) LV.merge(getLVForDecl(Template, computation)); continue; case TemplateArgument::Pack: LV.merge(getLVForTemplateArgumentList(Arg.getPackAsArray(), computation)); continue; } llvm_unreachable("bad template argument kind"); } return LV; } static LinkageInfo getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, LVComputationKind computation) { return getLVForTemplateArgumentList(TArgs.asArray(), computation); } static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn, const FunctionTemplateSpecializationInfo *specInfo) { // Include visibility from the template parameters and arguments // only if this is not an explicit instantiation or specialization // with direct explicit visibility. (Implicit instantiations won't // have a direct attribute.) if (!specInfo->isExplicitInstantiationOrSpecialization()) return true; return !fn->hasAttr(); } /// Merge in template-related linkage and visibility for the given /// function template specialization. /// /// We don't need a computation kind here because we can assume /// LVForValue. /// /// \param[out] LV the computation to use for the parent static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, const FunctionTemplateSpecializationInfo *specInfo, LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(fn, specInfo); // Merge information from the template parameters. FunctionTemplateDecl *temp = specInfo->getTemplate(); LinkageInfo tempLV = getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); // Merge information from the template arguments. const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation); LV.mergeMaybeWithVisibility(argsLV, considerVisibility); } /// Does the given declaration have a direct visibility attribute /// that would match the given rules? static bool hasDirectVisibilityAttribute(const NamedDecl *D, LVComputationKind computation) { switch (computation) { case LVForType: case LVForExplicitType: if (D->hasAttr()) return true; // fallthrough case LVForValue: case LVForExplicitValue: if (D->hasAttr()) return true; return false; case LVForLinkageOnly: return false; } llvm_unreachable("bad visibility computation kind"); } /// Should we consider visibility associated with the template /// arguments and parameters of the given class template specialization? static bool shouldConsiderTemplateVisibility( const ClassTemplateSpecializationDecl *spec, LVComputationKind computation) { // Include visibility from the template parameters and arguments // only if this is not an explicit instantiation or specialization // with direct explicit visibility (and note that implicit // instantiations won't have a direct attribute). // // Furthermore, we want to ignore template parameters and arguments // for an explicit specialization when computing the visibility of a // member thereof with explicit visibility. // // This is a bit complex; let's unpack it. // // An explicit class specialization is an independent, top-level // declaration. As such, if it or any of its members has an // explicit visibility attribute, that must directly express the // user's intent, and we should honor it. The same logic applies to // an explicit instantiation of a member of such a thing. // Fast path: if this is not an explicit instantiation or // specialization, we always want to consider template-related // visibility restrictions. if (!spec->isExplicitInstantiationOrSpecialization()) return true; // This is the 'member thereof' check. if (spec->isExplicitSpecialization() && hasExplicitVisibilityAlready(computation)) return false; return !hasDirectVisibilityAttribute(spec, computation); } /// Merge in template-related linkage and visibility for the given /// class template specialization. static void mergeTemplateLV(LinkageInfo &LV, const ClassTemplateSpecializationDecl *spec, LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation); // Merge information from the template parameters, but ignore // visibility if we're only considering template arguments. ClassTemplateDecl *temp = spec->getSpecializedTemplate(); LinkageInfo tempLV = getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility && !hasExplicitVisibilityAlready(computation)); // Merge information from the template arguments. We ignore // template-argument visibility if we've got an explicit // instantiation with a visibility attribute. const TemplateArgumentList &templateArgs = spec->getTemplateArgs(); LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation); if (considerVisibility) LV.mergeVisibility(argsLV); LV.mergeExternalVisibility(argsLV); } /// Should we consider visibility associated with the template /// arguments and parameters of the given variable template /// specialization? As usual, follow class template specialization /// logic up to initialization. static bool shouldConsiderTemplateVisibility( const VarTemplateSpecializationDecl *spec, LVComputationKind computation) { // Include visibility from the template parameters and arguments // only if this is not an explicit instantiation or specialization // with direct explicit visibility (and note that implicit // instantiations won't have a direct attribute). if (!spec->isExplicitInstantiationOrSpecialization()) return true; // An explicit variable specialization is an independent, top-level // declaration. As such, if it has an explicit visibility attribute, // that must directly express the user's intent, and we should honor // it. if (spec->isExplicitSpecialization() && hasExplicitVisibilityAlready(computation)) return false; return !hasDirectVisibilityAttribute(spec, computation); } /// Merge in template-related linkage and visibility for the given /// variable template specialization. As usual, follow class template /// specialization logic up to initialization. static void mergeTemplateLV(LinkageInfo &LV, const VarTemplateSpecializationDecl *spec, LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation); // Merge information from the template parameters, but ignore // visibility if we're only considering template arguments. VarTemplateDecl *temp = spec->getSpecializedTemplate(); LinkageInfo tempLV = getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility && !hasExplicitVisibilityAlready(computation)); // Merge information from the template arguments. We ignore // template-argument visibility if we've got an explicit // instantiation with a visibility attribute. const TemplateArgumentList &templateArgs = spec->getTemplateArgs(); LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation); if (considerVisibility) LV.mergeVisibility(argsLV); LV.mergeExternalVisibility(argsLV); } static bool useInlineVisibilityHidden(const NamedDecl *D) { // FIXME: we should warn if -fvisibility-inlines-hidden is used with c. const LangOptions &Opts = D->getASTContext().getLangOpts(); if (!Opts.CPlusPlus || !Opts.InlineVisibilityHidden) return false; const auto *FD = dyn_cast(D); if (!FD) return false; TemplateSpecializationKind TSK = TSK_Undeclared; if (FunctionTemplateSpecializationInfo *spec = FD->getTemplateSpecializationInfo()) { TSK = spec->getTemplateSpecializationKind(); } else if (MemberSpecializationInfo *MSI = FD->getMemberSpecializationInfo()) { TSK = MSI->getTemplateSpecializationKind(); } const FunctionDecl *Def = nullptr; // InlineVisibilityHidden only applies to definitions, and // isInlined() only gives meaningful answers on definitions // anyway. return TSK != TSK_ExplicitInstantiationDeclaration && TSK != TSK_ExplicitInstantiationDefinition && FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr(); } template static bool isFirstInExternCContext(T *D) { const T *First = D->getFirstDecl(); return First->isInExternCContext(); } static bool isSingleLineLanguageLinkage(const Decl &D) { if (const auto *SD = dyn_cast(D.getDeclContext())) if (!SD->hasBraces()) return true; return false; } static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); // C++ [basic.link]p3: // A name having namespace scope (3.3.6) has internal linkage if it // is the name of // - an object, reference, function or function template that is // explicitly declared static; or, // (This bullet corresponds to C99 6.2.2p3.) if (const auto *Var = dyn_cast(D)) { // Explicitly declared static. if (Var->getStorageClass() == SC_Static) return LinkageInfo::internal(); // - a non-inline, non-volatile object or reference that is explicitly // declared const or constexpr and neither explicitly declared extern // nor previously declared to have external linkage; or (there is no // equivalent in C99) if (Context.getLangOpts().CPlusPlus && Var->getType().isConstQualified() && !Var->getType().isVolatileQualified() && !Var->isInline()) { const VarDecl *PrevVar = Var->getPreviousDecl(); if (PrevVar) return getLVForDecl(PrevVar, computation); if (Var->getStorageClass() != SC_Extern && Var->getStorageClass() != SC_PrivateExtern && !isSingleLineLanguageLinkage(*Var)) return LinkageInfo::internal(); } for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar; PrevVar = PrevVar->getPreviousDecl()) { if (PrevVar->getStorageClass() == SC_PrivateExtern && Var->getStorageClass() == SC_None) return PrevVar->getLinkageAndVisibility(); // Explicitly declared static. if (PrevVar->getStorageClass() == SC_Static) return LinkageInfo::internal(); } } else if (const FunctionDecl *Function = D->getAsFunction()) { // C++ [temp]p4: // A non-member function template can have internal linkage; any // other template name shall have external linkage. // Explicitly declared static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) return LinkageInfo(InternalLinkage, DefaultVisibility, false); } else if (const auto *IFD = dyn_cast(D)) { // - a data member of an anonymous union. const VarDecl *VD = IFD->getVarDecl(); assert(VD && "Expected a VarDecl in this IndirectFieldDecl!"); return getLVForNamespaceScopeDecl(VD, computation); } assert(!isa(D) && "Didn't expect a FieldDecl!"); if (D->isInAnonymousNamespace()) { const auto *Var = dyn_cast(D); const auto *Func = dyn_cast(D); // FIXME: In C++11 onwards, anonymous namespaces should give decls // within them internal linkage, not unique external linkage. if ((!Var || !isFirstInExternCContext(Var)) && (!Func || !isFirstInExternCContext(Func))) return LinkageInfo::uniqueExternal(); } // Set up the defaults. // C99 6.2.2p5: // If the declaration of an identifier for an object has file // scope and no storage-class specifier, its linkage is // external. LinkageInfo LV; if (!hasExplicitVisibilityAlready(computation)) { if (Optional Vis = getExplicitVisibility(D, computation)) { LV.mergeVisibility(*Vis, true); } else { // If we're declared in a namespace with a visibility attribute, // use that namespace's visibility, and it still counts as explicit. for (const DeclContext *DC = D->getDeclContext(); !isa(DC); DC = DC->getParent()) { const auto *ND = dyn_cast(DC); if (!ND) continue; if (Optional Vis = getExplicitVisibility(ND, computation)) { LV.mergeVisibility(*Vis, true); break; } } } // Add in global settings if the above didn't give us direct visibility. if (!LV.isVisibilityExplicit()) { // Use global type/value visibility as appropriate. Visibility globalVisibility; if (computation == LVForValue) { globalVisibility = Context.getLangOpts().getValueVisibilityMode(); } else { assert(computation == LVForType); globalVisibility = Context.getLangOpts().getTypeVisibilityMode(); } LV.mergeVisibility(globalVisibility, /*explicit*/ false); // If we're paying attention to global visibility, apply // -finline-visibility-hidden if this is an inline method. if (useInlineVisibilityHidden(D)) LV.mergeVisibility(HiddenVisibility, true); } } // C++ [basic.link]p4: // A name having namespace scope has external linkage if it is the // name of // // - an object or reference, unless it has internal linkage; or if (const auto *Var = dyn_cast(D)) { // GCC applies the following optimization to variables and static // data members, but not to functions: // // Modify the variable's LV by the LV of its type unless this is // C or extern "C". This follows from [basic.link]p9: // A type without linkage shall not be used as the type of a // variable or function with external linkage unless // - the entity has C language linkage, or // - the entity is declared within an unnamed namespace, or // - the entity is not used or is defined in the same // translation unit. // and [basic.link]p10: // ...the types specified by all declarations referring to a // given variable or function shall be identical... // C does not have an equivalent rule. // // Ignore this if we've got an explicit attribute; the user // probably knows what they're doing. // // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); if (TypeLV.getLinkage() != ExternalLinkage) return LinkageInfo::uniqueExternal(); if (!LV.isVisibilityExplicit()) LV.mergeVisibility(TypeLV); } if (Var->getStorageClass() == SC_PrivateExtern) LV.mergeVisibility(HiddenVisibility, true); // Note that Sema::MergeVarDecl already takes care of implementing // C99 6.2.2p4 and propagating the visibility attribute, so we don't have // to do it here. // As per function and class template specializations (below), // consider LV for the template and template arguments. We're at file // scope, so we do not need to worry about nested specializations. if (const auto *spec = dyn_cast(Var)) { mergeTemplateLV(LV, spec, computation); } // - a function, unless it has internal linkage; or } else if (const auto *Function = dyn_cast(D)) { // In theory, we can modify the function's LV by the LV of its // type unless it has C linkage (see comment above about variables // for justification). In practice, GCC doesn't do this, so it's // just too painful to make work. if (Function->getStorageClass() == SC_PrivateExtern) LV.mergeVisibility(HiddenVisibility, true); // Note that Sema::MergeCompatibleFunctionDecls already takes care of // merging storage classes and visibility attributes, so we don't have to // look at previous decls in here. // In C++, then if the type of the function uses a type with // unique-external linkage, it's not legally usable from outside // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. if (Context.getLangOpts().CPlusPlus && !Function->isInExternCContext()) { // Only look at the type-as-written. If this function has an auto-deduced // return type, we can't compute the linkage of that type because it could // require looking at the linkage of this function, and we don't need this // for correctness because the type is not part of the function's // signature. // FIXME: This is a hack. We should be able to solve this circularity and // the one in getLVForClassMember for Functions some other way. QualType TypeAsWritten = Function->getType(); if (TypeSourceInfo *TSI = Function->getTypeSourceInfo()) TypeAsWritten = TSI->getType(); if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); } // Consider LV from the template and the template arguments. // We're at file scope, so we do not need to worry about nested // specializations. if (FunctionTemplateSpecializationInfo *specInfo = Function->getTemplateSpecializationInfo()) { mergeTemplateLV(LV, Function, specInfo, computation); } // - a named class (Clause 9), or an unnamed class defined in a // typedef declaration in which the class has the typedef name // for linkage purposes (7.1.3); or // - a named enumeration (7.2), or an unnamed enumeration // defined in a typedef declaration in which the enumeration // has the typedef name for linkage purposes (7.1.3); or } else if (const auto *Tag = dyn_cast(D)) { // Unnamed tags have no linkage. if (!Tag->hasNameForLinkage()) return LinkageInfo::none(); // If this is a class template specialization, consider the // linkage of the template and template arguments. We're at file // scope, so we do not need to worry about nested specializations. if (const auto *spec = dyn_cast(Tag)) { mergeTemplateLV(LV, spec, computation); } // - an enumerator belonging to an enumeration with external linkage; } else if (isa(D)) { LinkageInfo EnumLV = getLVForDecl(cast(D->getDeclContext()), computation); if (!isExternalFormalLinkage(EnumLV.getLinkage())) return LinkageInfo::none(); LV.merge(EnumLV); // - a template, unless it is a function template that has // internal linkage (Clause 14); } else if (const auto *temp = dyn_cast(D)) { bool considerVisibility = !hasExplicitVisibilityAlready(computation); LinkageInfo tempLV = getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); // - a namespace (7.3), unless it is declared within an unnamed // namespace. } else if (isa(D) && !D->isInAnonymousNamespace()) { return LV; // By extension, we assign external linkage to Objective-C // interfaces. } else if (isa(D)) { // fallout } else if (auto *TD = dyn_cast(D)) { // A typedef declaration has linkage if it gives a type a name for // linkage purposes. if (!TD->getAnonDeclWithTypedefName(/*AnyRedecl*/true)) return LinkageInfo::none(); // Everything not covered here has no linkage. } else { return LinkageInfo::none(); } // If we ended up with non-external linkage, visibility should // always be default. if (LV.getLinkage() != ExternalLinkage) return LinkageInfo(LV.getLinkage(), DefaultVisibility, false); return LV; } static LinkageInfo getLVForClassMember(const NamedDecl *D, LVComputationKind computation) { // Only certain class members have linkage. Note that fields don't // really have linkage, but it's convenient to say they do for the // purposes of calculating linkage of pointer-to-data-member // template arguments. // // Templates also don't officially have linkage, but since we ignore // the C++ standard and look at template arguments when determining // linkage and visibility of a template specialization, we might hit // a template template argument that way. If we do, we need to // consider its linkage. if (!(isa(D) || isa(D) || isa(D) || isa(D) || isa(D) || isa(D))) return LinkageInfo::none(); LinkageInfo LV; // If we have an explicit visibility attribute, merge that in. if (!hasExplicitVisibilityAlready(computation)) { if (Optional Vis = getExplicitVisibility(D, computation)) LV.mergeVisibility(*Vis, true); // If we're paying attention to global visibility, apply // -finline-visibility-hidden if this is an inline method. // // Note that we do this before merging information about // the class visibility. if (!LV.isVisibilityExplicit() && useInlineVisibilityHidden(D)) LV.mergeVisibility(HiddenVisibility, true); } // If this class member has an explicit visibility attribute, the only // thing that can change its visibility is the template arguments, so // only look for them when processing the class. LVComputationKind classComputation = computation; if (LV.isVisibilityExplicit()) classComputation = withExplicitVisibilityAlready(computation); LinkageInfo classLV = getLVForDecl(cast(D->getDeclContext()), classComputation); // If the class already has unique-external linkage, we can't improve. if (classLV.getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); if (!isExternallyVisible(classLV.getLinkage())) return LinkageInfo::none(); // Otherwise, don't merge in classLV yet, because in certain cases // we need to completely ignore the visibility from it. // Specifically, if this decl exists and has an explicit attribute. const NamedDecl *explicitSpecSuppressor = nullptr; if (const auto *MD = dyn_cast(D)) { // If the type of the function uses a type with unique-external // linkage, it's not legally usable from outside this translation unit. // But only look at the type-as-written. If this function has an // auto-deduced return type, we can't compute the linkage of that type // because it could require looking at the linkage of this function, and we // don't need this for correctness because the type is not part of the // function's signature. // FIXME: This is a hack. We should be able to solve this circularity and // the one in getLVForNamespaceScopeDecl for Functions some other way. { QualType TypeAsWritten = MD->getType(); if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) TypeAsWritten = TSI->getType(); if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); } // If this is a method template specialization, use the linkage for // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *spec = MD->getTemplateSpecializationInfo()) { mergeTemplateLV(LV, MD, spec, computation); if (spec->isExplicitSpecialization()) { explicitSpecSuppressor = MD; } else if (isExplicitMemberSpecialization(spec->getTemplate())) { explicitSpecSuppressor = spec->getTemplate()->getTemplatedDecl(); } } else if (isExplicitMemberSpecialization(MD)) { explicitSpecSuppressor = MD; } } else if (const auto *RD = dyn_cast(D)) { if (const auto *spec = dyn_cast(RD)) { mergeTemplateLV(LV, spec, computation); if (spec->isExplicitSpecialization()) { explicitSpecSuppressor = spec; } else { const ClassTemplateDecl *temp = spec->getSpecializedTemplate(); if (isExplicitMemberSpecialization(temp)) { explicitSpecSuppressor = temp->getTemplatedDecl(); } } } else if (isExplicitMemberSpecialization(RD)) { explicitSpecSuppressor = RD; } // Static data members. } else if (const auto *VD = dyn_cast(D)) { if (const auto *spec = dyn_cast(VD)) mergeTemplateLV(LV, spec, computation); // Modify the variable's linkage by its type, but ignore the // type's visibility unless it's a definition. LinkageInfo typeLV = getLVForType(*VD->getType(), computation); if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()) LV.mergeVisibility(typeLV); LV.mergeExternalVisibility(typeLV); if (isExplicitMemberSpecialization(VD)) { explicitSpecSuppressor = VD; } // Template members. } else if (const auto *temp = dyn_cast(D)) { bool considerVisibility = (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit() && !hasExplicitVisibilityAlready(computation)); LinkageInfo tempLV = getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); if (const auto *redeclTemp = dyn_cast(temp)) { if (isExplicitMemberSpecialization(redeclTemp)) { explicitSpecSuppressor = temp->getTemplatedDecl(); } } } // We should never be looking for an attribute directly on a template. assert(!explicitSpecSuppressor || !isa(explicitSpecSuppressor)); // If this member is an explicit member specialization, and it has // an explicit attribute, ignore visibility from the parent. bool considerClassVisibility = true; if (explicitSpecSuppressor && // optimization: hasDVA() is true only with explicit visibility. LV.isVisibilityExplicit() && classLV.getVisibility() != DefaultVisibility && hasDirectVisibilityAttribute(explicitSpecSuppressor, computation)) { considerClassVisibility = false; } // Finally, merge in information from the class. LV.mergeMaybeWithVisibility(classLV, considerClassVisibility); return LV; } void NamedDecl::anchor() { } static LinkageInfo computeLVForDecl(const NamedDecl *D, LVComputationKind computation); bool NamedDecl::isLinkageValid() const { if (!hasCachedLinkage()) return true; return computeLVForDecl(this, LVForLinkageOnly).getLinkage() == getCachedLinkage(); } ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const { StringRef name = getName(); if (name.empty()) return SFF_None; if (name.front() == 'C') if (name == "CFStringCreateWithFormat" || name == "CFStringCreateWithFormatAndArguments" || name == "CFStringAppendFormat" || name == "CFStringAppendFormatAndArguments") return SFF_CFString; return SFF_None; } Linkage NamedDecl::getLinkageInternal() const { // We don't care about visibility here, so ask for the cheapest // possible visibility analysis. return getLVForDecl(this, LVForLinkageOnly).getLinkage(); } LinkageInfo NamedDecl::getLinkageAndVisibility() const { LVComputationKind computation = (usesTypeVisibility(this) ? LVForType : LVForValue); return getLVForDecl(this, computation); } static Optional getExplicitVisibilityAux(const NamedDecl *ND, NamedDecl::ExplicitVisibilityKind kind, bool IsMostRecent) { assert(!IsMostRecent || ND == ND->getMostRecentDecl()); // Check the declaration itself first. if (Optional V = getVisibilityOf(ND, kind)) return V; // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. if (const auto *RD = dyn_cast(ND)) { CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } // If there wasn't explicit visibility there, and this is a // specialization of a class template, check for visibility // on the pattern. if (const auto *spec = dyn_cast(ND)) return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(), kind); // Use the most recent declaration. if (!IsMostRecent && !isa(ND)) { const NamedDecl *MostRecent = ND->getMostRecentDecl(); if (MostRecent != ND) return getExplicitVisibilityAux(MostRecent, kind, true); } if (const auto *Var = dyn_cast(ND)) { if (Var->isStaticDataMember()) { VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } if (const auto *VTSD = dyn_cast(Var)) return getVisibilityOf(VTSD->getSpecializedTemplate()->getTemplatedDecl(), kind); return None; } // Also handle function template specializations. if (const auto *fn = dyn_cast(ND)) { // If the function is a specialization of a template with an // explicit visibility attribute, use that. if (FunctionTemplateSpecializationInfo *templateInfo = fn->getTemplateSpecializationInfo()) return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(), kind); // If the function is a member of a specialization of a class template // and the corresponding decl has explicit visibility, use that. FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); return None; } // The visibility of a template is stored in the templated decl. if (const auto *TD = dyn_cast(ND)) return getVisibilityOf(TD->getTemplatedDecl(), kind); return None; } Optional NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { return getExplicitVisibilityAux(this, kind, false); } static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, LVComputationKind computation) { // This lambda has its linkage/visibility determined by its owner. if (ContextDecl) { if (isa(ContextDecl)) DC = ContextDecl->getDeclContext()->getRedeclContext(); else return getLVForDecl(cast(ContextDecl), computation); } if (const auto *ND = dyn_cast(DC)) return getLVForDecl(ND, computation); return LinkageInfo::external(); } static LinkageInfo getLVForLocalDecl(const NamedDecl *D, LVComputationKind computation) { if (const auto *Function = dyn_cast(D)) { if (Function->isInAnonymousNamespace() && !Function->isInExternCContext()) return LinkageInfo::uniqueExternal(); // This is a "void f();" which got merged with a file static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) return LinkageInfo::internal(); LinkageInfo LV; if (!hasExplicitVisibilityAlready(computation)) { if (Optional Vis = getExplicitVisibility(Function, computation)) LV.mergeVisibility(*Vis, true); } // Note that Sema::MergeCompatibleFunctionDecls already takes care of // merging storage classes and visibility attributes, so we don't have to // look at previous decls in here. return LV; } if (const auto *Var = dyn_cast(D)) { if (Var->hasExternalStorage()) { if (Var->isInAnonymousNamespace() && !Var->isInExternCContext()) return LinkageInfo::uniqueExternal(); LinkageInfo LV; if (Var->getStorageClass() == SC_PrivateExtern) LV.mergeVisibility(HiddenVisibility, true); else if (!hasExplicitVisibilityAlready(computation)) { if (Optional Vis = getExplicitVisibility(Var, computation)) LV.mergeVisibility(*Vis, true); } if (const VarDecl *Prev = Var->getPreviousDecl()) { LinkageInfo PrevLV = getLVForDecl(Prev, computation); if (PrevLV.getLinkage()) LV.setLinkage(PrevLV.getLinkage()); LV.mergeVisibility(PrevLV); } return LV; } if (!Var->isStaticLocal()) return LinkageInfo::none(); } ASTContext &Context = D->getASTContext(); if (!Context.getLangOpts().CPlusPlus) return LinkageInfo::none(); const Decl *OuterD = getOutermostFuncOrBlockContext(D); if (!OuterD || OuterD->isInvalidDecl()) return LinkageInfo::none(); LinkageInfo LV; if (const auto *BD = dyn_cast(OuterD)) { if (!BD->getBlockManglingNumber()) return LinkageInfo::none(); LV = getLVForClosure(BD->getDeclContext()->getRedeclContext(), BD->getBlockManglingContextDecl(), computation); } else { const auto *FD = cast(OuterD); if (!FD->isInlined() && !isTemplateInstantiation(FD->getTemplateSpecializationKind())) return LinkageInfo::none(); LV = getLVForDecl(FD, computation); } if (!isExternallyVisible(LV.getLinkage())) return LinkageInfo::none(); return LinkageInfo(VisibleNoLinkage, LV.getVisibility(), LV.isVisibilityExplicit()); } static inline const CXXRecordDecl* getOutermostEnclosingLambda(const CXXRecordDecl *Record) { const CXXRecordDecl *Ret = Record; while (Record && Record->isLambda()) { Ret = Record; if (!Record->getParent()) break; // Get the Containing Class of this Lambda Class Record = dyn_cast_or_null( Record->getParent()->getParent()); } return Ret; } static LinkageInfo computeLVForDecl(const NamedDecl *D, LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr()) return LinkageInfo::internal(); // Objective-C: treat all Objective-C declarations as having external // linkage. switch (D->getKind()) { default: break; // Per C++ [basic.link]p2, only the names of objects, references, // functions, types, templates, namespaces, and values ever have linkage. // // Note that the name of a typedef, namespace alias, using declaration, // and so on are not the name of the corresponding type, namespace, or // declaration, so they do *not* have linkage. case Decl::ImplicitParam: case Decl::Label: case Decl::NamespaceAlias: case Decl::ParmVar: case Decl::Using: case Decl::UsingShadow: case Decl::UsingDirective: return LinkageInfo::none(); case Decl::EnumConstant: // C++ [basic.link]p4: an enumerator has the linkage of its enumeration. return getLVForDecl(cast(D->getDeclContext()), computation); case Decl::Typedef: case Decl::TypeAlias: // A typedef declaration has linkage if it gives a type a name for // linkage purposes. if (!D->getASTContext().getLangOpts().CPlusPlus || !cast(D) ->getAnonDeclWithTypedefName(/*AnyRedecl*/true)) return LinkageInfo::none(); break; case Decl::TemplateTemplateParm: // count these as external case Decl::NonTypeTemplateParm: case Decl::ObjCAtDefsField: case Decl::ObjCCategory: case Decl::ObjCCategoryImpl: case Decl::ObjCCompatibleAlias: case Decl::ObjCImplementation: case Decl::ObjCMethod: case Decl::ObjCProperty: case Decl::ObjCPropertyImpl: case Decl::ObjCProtocol: return LinkageInfo::external(); case Decl::CXXRecord: { const auto *Record = cast(D); if (Record->isLambda()) { if (!Record->getLambdaManglingNumber()) { // This lambda has no mangling number, so it's internal. return LinkageInfo::internal(); } // This lambda has its linkage/visibility determined: // - either by the outermost lambda if that lambda has no mangling // number. // - or by the parent of the outer most lambda // This prevents infinite recursion in settings such as nested lambdas // used in NSDMI's, for e.g. // struct L { // int t{}; // int t2 = ([](int a) { return [](int b) { return b; };})(t)(t); // }; const CXXRecordDecl *OuterMostLambda = getOutermostEnclosingLambda(Record); if (!OuterMostLambda->getLambdaManglingNumber()) return LinkageInfo::internal(); return getLVForClosure( OuterMostLambda->getDeclContext()->getRedeclContext(), OuterMostLambda->getLambdaContextDecl(), computation); } break; } } // Handle linkage for namespace-scope names. if (D->getDeclContext()->getRedeclContext()->isFileContext()) return getLVForNamespaceScopeDecl(D, computation); // C++ [basic.link]p5: // In addition, a member function, static data member, a named // class or enumeration of class scope, or an unnamed class or // enumeration defined in a class-scope typedef declaration such // that the class or enumeration has the typedef name for linkage // purposes (7.1.3), has external linkage if the name of the class // has external linkage. if (D->getDeclContext()->isRecord()) return getLVForClassMember(D, computation); // C++ [basic.link]p6: // The name of a function declared in block scope and the name of // an object declared by a block scope extern declaration have // linkage. If there is a visible declaration of an entity with // linkage having the same name and type, ignoring entities // declared outside the innermost enclosing namespace scope, the // block scope declaration declares that same entity and receives // the linkage of the previous declaration. If there is more than // one such matching entity, the program is ill-formed. Otherwise, // if no matching entity is found, the block scope entity receives // external linkage. if (D->getDeclContext()->isFunctionOrMethod()) return getLVForLocalDecl(D, computation); // C++ [basic.link]p6: // Names not covered by these rules have no linkage. return LinkageInfo::none(); } namespace clang { class LinkageComputer { public: static LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr()) return LinkageInfo::internal(); if (computation == LVForLinkageOnly && D->hasCachedLinkage()) return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); LinkageInfo LV = computeLVForDecl(D, computation); if (D->hasCachedLinkage()) assert(D->getCachedLinkage() == LV.getLinkage()); D->setCachedLinkage(LV.getLinkage()); #ifndef NDEBUG // In C (because of gnu inline) and in c++ with microsoft extensions an // static can follow an extern, so we can have two decls with different // linkages. const LangOptions &Opts = D->getASTContext().getLangOpts(); if (!Opts.CPlusPlus || Opts.MicrosoftExt) return LV; // We have just computed the linkage for this decl. By induction we know // that all other computed linkages match, check that the one we just // computed also does. NamedDecl *Old = nullptr; for (auto I : D->redecls()) { auto *T = cast(I); if (T == D) continue; if (!T->isInvalidDecl() && T->hasCachedLinkage()) { Old = T; break; } } assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); #endif return LV; } }; } static LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation) { return clang::LinkageComputer::getLVForDecl(D, computation); } void NamedDecl::printName(raw_ostream &os) const { os << Name; } std::string NamedDecl::getQualifiedNameAsString() const { std::string QualName; llvm::raw_string_ostream OS(QualName); printQualifiedName(OS, getASTContext().getPrintingPolicy()); return OS.str(); } void NamedDecl::printQualifiedName(raw_ostream &OS) const { printQualifiedName(OS, getASTContext().getPrintingPolicy()); } void NamedDecl::printQualifiedName(raw_ostream &OS, const PrintingPolicy &P) const { const DeclContext *Ctx = getDeclContext(); // For ObjC methods, look through categories and use the interface as context. if (auto *MD = dyn_cast(this)) if (auto *ID = MD->getClassInterface()) Ctx = ID; if (Ctx->isFunctionOrMethod()) { printName(OS); return; } typedef SmallVector ContextsTy; ContextsTy Contexts; // Collect contexts. while (Ctx && isa(Ctx)) { Contexts.push_back(Ctx); Ctx = Ctx->getParent(); } for (const DeclContext *DC : reverse(Contexts)) { if (const auto *Spec = dyn_cast(DC)) { OS << Spec->getName(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); TemplateSpecializationType::PrintTemplateArgumentList( OS, TemplateArgs.asArray(), P); } else if (const auto *ND = dyn_cast(DC)) { if (P.SuppressUnwrittenScope && (ND->isAnonymousNamespace() || ND->isInline())) continue; if (ND->isAnonymousNamespace()) { OS << (P.MSVCFormatting ? "`anonymous namespace\'" : "(anonymous namespace)"); } else OS << *ND; } else if (const auto *RD = dyn_cast(DC)) { if (!RD->getIdentifier()) OS << "(anonymous " << RD->getKindName() << ')'; else OS << *RD; } else if (const auto *FD = dyn_cast(DC)) { const FunctionProtoType *FT = nullptr; if (FD->hasWrittenPrototype()) FT = dyn_cast(FD->getType()->castAs()); OS << *FD << '('; if (FT) { unsigned NumParams = FD->getNumParams(); for (unsigned i = 0; i < NumParams; ++i) { if (i) OS << ", "; OS << FD->getParamDecl(i)->getType().stream(P); } if (FT->isVariadic()) { if (NumParams > 0) OS << ", "; OS << "..."; } } OS << ')'; } else if (const auto *ED = dyn_cast(DC)) { // C++ [dcl.enum]p10: Each enum-name and each unscoped // enumerator is declared in the scope that immediately contains // the enum-specifier. Each scoped enumerator is declared in the // scope of the enumeration. if (ED->isScoped() || ED->getIdentifier()) OS << *ED; else continue; } else { OS << *cast(DC); } OS << "::"; } if (getDeclName() || isa(this)) OS << *this; else OS << "(anonymous)"; } void NamedDecl::getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { if (Qualified) printQualifiedName(OS, Policy); else printName(OS); } template static bool isRedeclarableImpl(Redeclarable *) { return true; } static bool isRedeclarableImpl(...) { return false; } static bool isRedeclarable(Decl::Kind K) { switch (K) { #define DECL(Type, Base) \ case Decl::Type: \ return isRedeclarableImpl((Type##Decl *)nullptr); #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" } llvm_unreachable("unknown decl kind"); } bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const { assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch"); // Never replace one imported declaration with another; we need both results // when re-exporting. if (OldD->isFromASTFile() && isFromASTFile()) return false; // A kind mismatch implies that the declaration is not replaced. if (OldD->getKind() != getKind()) return false; // For method declarations, we never replace. (Why?) if (isa(this)) return false; // For parameters, pick the newer one. This is either an error or (in // Objective-C) permitted as an extension. if (isa(this)) return true; // Inline namespaces can give us two declarations with the same // name and kind in the same scope but different contexts; we should // keep both declarations in this case. if (!this->getDeclContext()->getRedeclContext()->Equals( OldD->getDeclContext()->getRedeclContext())) return false; // Using declarations can be replaced if they import the same name from the // same context. if (auto *UD = dyn_cast(this)) { ASTContext &Context = getASTContext(); return Context.getCanonicalNestedNameSpecifier(UD->getQualifier()) == Context.getCanonicalNestedNameSpecifier( cast(OldD)->getQualifier()); } if (auto *UUVD = dyn_cast(this)) { ASTContext &Context = getASTContext(); return Context.getCanonicalNestedNameSpecifier(UUVD->getQualifier()) == Context.getCanonicalNestedNameSpecifier( cast(OldD)->getQualifier()); } // UsingDirectiveDecl's are not really NamedDecl's, and all have same name. // They can be replaced if they nominate the same namespace. // FIXME: Is this true even if they have different module visibility? if (auto *UD = dyn_cast(this)) return UD->getNominatedNamespace()->getOriginalNamespace() == cast(OldD)->getNominatedNamespace() ->getOriginalNamespace(); if (isRedeclarable(getKind())) { if (getCanonicalDecl() != OldD->getCanonicalDecl()) return false; if (IsKnownNewer) return true; // Check whether this is actually newer than OldD. We want to keep the // newer declaration. This loop will usually only iterate once, because // OldD is usually the previous declaration. for (auto D : redecls()) { if (D == OldD) break; // If we reach the canonical declaration, then OldD is not actually older // than this one. // // FIXME: In this case, we should not add this decl to the lookup table. if (D->isCanonicalDecl()) return false; } // It's a newer declaration of the same kind of declaration in the same // scope: we want this decl instead of the existing one. return true; } // In all other cases, we need to keep both declarations in case they have // different visibility. Any attempt to use the name will result in an // ambiguity if more than one is visible. return false; } bool NamedDecl::hasLinkage() const { return getFormalLinkage() != NoLinkage; } NamedDecl *NamedDecl::getUnderlyingDeclImpl() { NamedDecl *ND = this; while (auto *UD = dyn_cast(ND)) ND = UD->getTargetDecl(); if (auto *AD = dyn_cast(ND)) return AD->getClassInterface(); if (auto *AD = dyn_cast(ND)) return AD->getNamespace(); return ND; } bool NamedDecl::isCXXInstanceMember() const { if (!isCXXClassMember()) return false; const NamedDecl *D = this; if (isa(D)) D = cast(D)->getTargetDecl(); if (isa(D) || isa(D) || isa(D)) return true; if (const auto *MD = dyn_cast_or_null(D->getAsFunction())) return MD->isInstance(); return false; } //===----------------------------------------------------------------------===// // DeclaratorDecl Implementation //===----------------------------------------------------------------------===// template static SourceLocation getTemplateOrInnerLocStart(const DeclT *decl) { if (decl->getNumTemplateParameterLists() > 0) return decl->getTemplateParameterList(0)->getTemplateLoc(); else return decl->getInnerLocStart(); } SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { TypeSourceInfo *TSI = getTypeSourceInfo(); if (TSI) return TSI->getTypeLoc().getBeginLoc(); return SourceLocation(); } void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { if (QualifierLoc) { // Make sure the extended decl info is allocated. if (!hasExtInfo()) { // Save (non-extended) type source info pointer. auto *savedTInfo = DeclInfo.get(); // Allocate external info struct. DeclInfo = new (getASTContext()) ExtInfo; // Restore savedTInfo into (extended) decl info. getExtInfo()->TInfo = savedTInfo; } // Set qualifier info. getExtInfo()->QualifierLoc = QualifierLoc; } else { // Here Qualifier == 0, i.e., we are removing the qualifier (if any). if (hasExtInfo()) { if (getExtInfo()->NumTemplParamLists == 0) { // Save type source info pointer. TypeSourceInfo *savedTInfo = getExtInfo()->TInfo; // Deallocate the extended decl info. getASTContext().Deallocate(getExtInfo()); // Restore savedTInfo into (non-extended) decl info. DeclInfo = savedTInfo; } else getExtInfo()->QualifierLoc = QualifierLoc; } } } void DeclaratorDecl::setTemplateParameterListsInfo( ASTContext &Context, ArrayRef TPLists) { assert(!TPLists.empty()); // Make sure the extended decl info is allocated. if (!hasExtInfo()) { // Save (non-extended) type source info pointer. auto *savedTInfo = DeclInfo.get(); // Allocate external info struct. DeclInfo = new (getASTContext()) ExtInfo; // Restore savedTInfo into (extended) decl info. getExtInfo()->TInfo = savedTInfo; } // Set the template parameter lists info. getExtInfo()->setTemplateParameterListsInfo(Context, TPLists); } SourceLocation DeclaratorDecl::getOuterLocStart() const { return getTemplateOrInnerLocStart(this); } namespace { // Helper function: returns true if QT is or contains a type // having a postfix component. bool typeIsPostfix(clang::QualType QT) { while (true) { const Type* T = QT.getTypePtr(); switch (T->getTypeClass()) { default: return false; case Type::Pointer: QT = cast(T)->getPointeeType(); break; case Type::BlockPointer: QT = cast(T)->getPointeeType(); break; case Type::MemberPointer: QT = cast(T)->getPointeeType(); break; case Type::LValueReference: case Type::RValueReference: QT = cast(T)->getPointeeType(); break; case Type::PackExpansion: QT = cast(T)->getPattern(); break; case Type::Paren: case Type::ConstantArray: case Type::DependentSizedArray: case Type::IncompleteArray: case Type::VariableArray: case Type::FunctionProto: case Type::FunctionNoProto: return true; } } } } // namespace SourceRange DeclaratorDecl::getSourceRange() const { SourceLocation RangeEnd = getLocation(); if (TypeSourceInfo *TInfo = getTypeSourceInfo()) { // If the declaration has no name or the type extends past the name take the // end location of the type. if (!getDeclName() || typeIsPostfix(TInfo->getType())) RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); } return SourceRange(getOuterLocStart(), RangeEnd); } void QualifierInfo::setTemplateParameterListsInfo( ASTContext &Context, ArrayRef TPLists) { // Free previous template parameters (if any). if (NumTemplParamLists > 0) { Context.Deallocate(TemplParamLists); TemplParamLists = nullptr; NumTemplParamLists = 0; } // Set info on matched template parameter lists (if any). if (!TPLists.empty()) { TemplParamLists = new (Context) TemplateParameterList *[TPLists.size()]; NumTemplParamLists = TPLists.size(); std::copy(TPLists.begin(), TPLists.end(), TemplParamLists); } } //===----------------------------------------------------------------------===// // VarDecl Implementation //===----------------------------------------------------------------------===// const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { switch (SC) { case SC_None: break; case SC_Auto: return "auto"; case SC_Extern: return "extern"; case SC_PrivateExtern: return "__private_extern__"; case SC_Register: return "register"; case SC_Static: return "static"; } llvm_unreachable("Invalid storage class"); } VarDecl::VarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass SC) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), redeclarable_base(C), Init() { static_assert(sizeof(VarDeclBitfields) <= sizeof(unsigned), "VarDeclBitfields too large!"); static_assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned), "ParmVarDeclBitfields too large!"); static_assert(sizeof(NonParmVarDeclBitfields) <= sizeof(unsigned), "NonParmVarDeclBitfields too large!"); AllBits = 0; VarDeclBits.SClass = SC; // Everything else is implicitly initialized to false. } VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL, SourceLocation IdL, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S) { return new (C, DC) VarDecl(Var, C, DC, StartL, IdL, Id, T, TInfo, S); } VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) VarDecl(Var, C, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, SC_None); } void VarDecl::setStorageClass(StorageClass SC) { assert(isLegalForVariable(SC)); VarDeclBits.SClass = SC; } VarDecl::TLSKind VarDecl::getTLSKind() const { switch (VarDeclBits.TSCSpec) { case TSCS_unspecified: if (!hasAttr() && !(getASTContext().getLangOpts().OpenMPUseTLS && getASTContext().getTargetInfo().isTLSSupported() && hasAttr())) return TLS_None; return ((getASTContext().getLangOpts().isCompatibleWithMSVC( LangOptions::MSVC2015)) || hasAttr()) ? TLS_Dynamic : TLS_Static; case TSCS___thread: // Fall through. case TSCS__Thread_local: return TLS_Static; case TSCS_thread_local: return TLS_Dynamic; } llvm_unreachable("Unknown thread storage class specifier!"); } SourceRange VarDecl::getSourceRange() const { if (const Expr *Init = getInit()) { SourceLocation InitEnd = Init->getLocEnd(); // If Init is implicit, ignore its source range and fallback on // DeclaratorDecl::getSourceRange() to handle postfix elements. if (InitEnd.isValid() && InitEnd != getLocation()) return SourceRange(getOuterLocStart(), InitEnd); } return DeclaratorDecl::getSourceRange(); } template static LanguageLinkage getDeclLanguageLinkage(const T &D) { // C++ [dcl.link]p1: All function types, function names with external linkage, // and variable names with external linkage have a language linkage. if (!D.hasExternalFormalLinkage()) return NoLanguageLinkage; // Language linkage is a C++ concept, but saying that everything else in C has // C language linkage fits the implementation nicely. ASTContext &Context = D.getASTContext(); if (!Context.getLangOpts().CPlusPlus) return CLanguageLinkage; // C++ [dcl.link]p4: A C language linkage is ignored in determining the // language linkage of the names of class members and the function type of // class member functions. const DeclContext *DC = D.getDeclContext(); if (DC->isRecord()) return CXXLanguageLinkage; // If the first decl is in an extern "C" context, any other redeclaration // will have C language linkage. If the first one is not in an extern "C" // context, we would have reported an error for any other decl being in one. if (isFirstInExternCContext(&D)) return CLanguageLinkage; return CXXLanguageLinkage; } template static bool isDeclExternC(const T &D) { // Since the context is ignored for class members, they can only have C++ // language linkage or no language linkage. const DeclContext *DC = D.getDeclContext(); if (DC->isRecord()) { assert(D.getASTContext().getLangOpts().CPlusPlus); return false; } return D.getLanguageLinkage() == CLanguageLinkage; } LanguageLinkage VarDecl::getLanguageLinkage() const { return getDeclLanguageLinkage(*this); } bool VarDecl::isExternC() const { return isDeclExternC(*this); } bool VarDecl::isInExternCContext() const { return getLexicalDeclContext()->isExternCContext(); } bool VarDecl::isInExternCXXContext() const { return getLexicalDeclContext()->isExternCXXContext(); } VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); } VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(ASTContext &C) const { // C++ [basic.def]p2: // A declaration is a definition unless [...] it contains the 'extern' // specifier or a linkage-specification and neither an initializer [...], // it declares a non-inline static data member in a class declaration [...], // it declares a static data member outside a class definition and the variable // was defined within the class with the constexpr specifier [...], // C++1y [temp.expl.spec]p15: // An explicit specialization of a static data member or an explicit // specialization of a static data member template is a definition if the // declaration includes an initializer; otherwise, it is a declaration. // // FIXME: How do you declare (but not define) a partial specialization of // a static data member template outside the containing class? if (isThisDeclarationADemotedDefinition()) return DeclarationOnly; if (isStaticDataMember()) { if (isOutOfLine() && !(getCanonicalDecl()->isInline() && getCanonicalDecl()->isConstexpr()) && (hasInit() || // If the first declaration is out-of-line, this may be an // instantiation of an out-of-line partial specialization of a variable // template for which we have not yet instantiated the initializer. (getFirstDecl()->isOutOfLine() ? getTemplateSpecializationKind() == TSK_Undeclared : getTemplateSpecializationKind() != TSK_ExplicitSpecialization) || isa(this))) return Definition; else if (!isOutOfLine() && isInline()) return Definition; else return DeclarationOnly; } // C99 6.7p5: // A definition of an identifier is a declaration for that identifier that // [...] causes storage to be reserved for that object. // Note: that applies for all non-file-scope objects. // C99 6.9.2p1: // If the declaration of an identifier for an object has file scope and an // initializer, the declaration is an external definition for the identifier if (hasInit()) return Definition; if (hasDefiningAttr()) return Definition; if (const auto *SAA = getAttr()) if (!SAA->isInherited()) return Definition; // A variable template specialization (other than a static data member // template or an explicit specialization) is a declaration until we // instantiate its initializer. if (isa(this) && getTemplateSpecializationKind() != TSK_ExplicitSpecialization) return DeclarationOnly; if (hasExternalStorage()) return DeclarationOnly; // [dcl.link] p7: // A declaration directly contained in a linkage-specification is treated // as if it contains the extern specifier for the purpose of determining // the linkage of the declared name and whether it is a definition. if (isSingleLineLanguageLinkage(*this)) return DeclarationOnly; // C99 6.9.2p2: // A declaration of an object that has file scope without an initializer, // and without a storage class specifier or the scs 'static', constitutes // a tentative definition. // No such thing in C++. if (!C.getLangOpts().CPlusPlus && isFileVarDecl()) return TentativeDefinition; // What's left is (in C, block-scope) declarations without initializers or // external storage. These are definitions. return Definition; } VarDecl *VarDecl::getActingDefinition() { DefinitionKind Kind = isThisDeclarationADefinition(); if (Kind != TentativeDefinition) return nullptr; VarDecl *LastTentative = nullptr; VarDecl *First = getFirstDecl(); for (auto I : First->redecls()) { Kind = I->isThisDeclarationADefinition(); if (Kind == Definition) return nullptr; else if (Kind == TentativeDefinition) LastTentative = I; } return LastTentative; } VarDecl *VarDecl::getDefinition(ASTContext &C) { VarDecl *First = getFirstDecl(); for (auto I : First->redecls()) { if (I->isThisDeclarationADefinition(C) == Definition) return I; } return nullptr; } VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const { DefinitionKind Kind = DeclarationOnly; const VarDecl *First = getFirstDecl(); for (auto I : First->redecls()) { Kind = std::max(Kind, I->isThisDeclarationADefinition(C)); if (Kind == Definition) break; } return Kind; } const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const { for (auto I : redecls()) { if (auto Expr = I->getInit()) { D = I; return Expr; } } return nullptr; } bool VarDecl::hasInit() const { if (auto *P = dyn_cast(this)) if (P->hasUnparsedDefaultArg() || P->hasUninstantiatedDefaultArg()) return false; return !Init.isNull(); } Expr *VarDecl::getInit() { if (!hasInit()) return nullptr; if (auto *S = Init.dyn_cast()) return cast(S); return cast_or_null(Init.get()->Value); } Stmt **VarDecl::getInitAddress() { if (auto *ES = Init.dyn_cast()) return &ES->Value; return Init.getAddrOfPtr1(); } bool VarDecl::isOutOfLine() const { if (Decl::isOutOfLine()) return true; if (!isStaticDataMember()) return false; // If this static data member was instantiated from a static data member of // a class template, check whether that static data member was defined // out-of-line. if (VarDecl *VD = getInstantiatedFromStaticDataMember()) return VD->isOutOfLine(); return false; } void VarDecl::setInit(Expr *I) { if (auto *Eval = Init.dyn_cast()) { Eval->~EvaluatedStmt(); getASTContext().Deallocate(Eval); } Init = I; } bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const { const LangOptions &Lang = C.getLangOpts(); if (!Lang.CPlusPlus) return false; // In C++11, any variable of reference type can be used in a constant // expression if it is initialized by a constant expression. if (Lang.CPlusPlus11 && getType()->isReferenceType()) return true; // Only const objects can be used in constant expressions in C++. C++98 does // not require the variable to be non-volatile, but we consider this to be a // defect. if (!getType().isConstQualified() || getType().isVolatileQualified()) return false; // In C++, const, non-volatile variables of integral or enumeration types // can be used in constant expressions. if (getType()->isIntegralOrEnumerationType()) return true; // Additionally, in C++11, non-volatile constexpr variables can be used in // constant expressions. return Lang.CPlusPlus11 && isConstexpr(); } /// Convert the initializer for this declaration to the elaborated EvaluatedStmt /// form, which contains extra information on the evaluated value of the /// initializer. EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const { auto *Eval = Init.dyn_cast(); if (!Eval) { // Note: EvaluatedStmt contains an APValue, which usually holds // resources not allocated from the ASTContext. We need to do some // work to avoid leaking those, but we do so in VarDecl::evaluateValue // where we can detect whether there's anything to clean up or not. Eval = new (getASTContext()) EvaluatedStmt; Eval->Value = Init.get(); Init = Eval; } return Eval; } APValue *VarDecl::evaluateValue() const { SmallVector Notes; return evaluateValue(Notes); } APValue *VarDecl::evaluateValue( SmallVectorImpl &Notes) const { EvaluatedStmt *Eval = ensureEvaluatedStmt(); // We only produce notes indicating why an initializer is non-constant the // first time it is evaluated. FIXME: The notes won't always be emitted the // first time we try evaluation, so might not be produced at all. if (Eval->WasEvaluated) return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated; const auto *Init = cast(Eval->Value); assert(!Init->isValueDependent()); if (Eval->IsEvaluating) { // FIXME: Produce a diagnostic for self-initialization. Eval->CheckedICE = true; Eval->IsICE = false; return nullptr; } Eval->IsEvaluating = true; bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(), this, Notes); // Ensure the computed APValue is cleaned up later if evaluation succeeded, // or that it's empty (so that there's nothing to clean up) if evaluation // failed. if (!Result) Eval->Evaluated = APValue(); else if (Eval->Evaluated.needsCleanup()) getASTContext().addDestruction(&Eval->Evaluated); Eval->IsEvaluating = false; Eval->WasEvaluated = true; // In C++11, we have determined whether the initializer was a constant // expression as a side-effect. if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) { Eval->CheckedICE = true; Eval->IsICE = Result && Notes.empty(); } return Result ? &Eval->Evaluated : nullptr; } APValue *VarDecl::getEvaluatedValue() const { if (EvaluatedStmt *Eval = Init.dyn_cast()) if (Eval->WasEvaluated) return &Eval->Evaluated; return nullptr; } bool VarDecl::isInitKnownICE() const { if (EvaluatedStmt *Eval = Init.dyn_cast()) return Eval->CheckedICE; return false; } bool VarDecl::isInitICE() const { assert(isInitKnownICE() && "Check whether we already know that the initializer is an ICE"); return Init.get()->IsICE; } bool VarDecl::checkInitIsICE() const { // Initializers of weak variables are never ICEs. if (isWeak()) return false; EvaluatedStmt *Eval = ensureEvaluatedStmt(); if (Eval->CheckedICE) // We have already checked whether this subexpression is an // integral constant expression. return Eval->IsICE; const auto *Init = cast(Eval->Value); assert(!Init->isValueDependent()); // In C++11, evaluate the initializer to check whether it's a constant // expression. if (getASTContext().getLangOpts().CPlusPlus11) { SmallVector Notes; evaluateValue(Notes); return Eval->IsICE; } // It's an ICE whether or not the definition we found is // out-of-line. See DR 721 and the discussion in Clang PR // 6206 for details. if (Eval->CheckingICE) return false; Eval->CheckingICE = true; Eval->IsICE = Init->isIntegerConstantExpr(getASTContext()); Eval->CheckingICE = false; Eval->CheckedICE = true; return Eval->IsICE; } template static DeclT *getDefinitionOrSelf(DeclT *D) { assert(D); if (auto *Def = D->getDefinition()) return Def; return D; } VarDecl *VarDecl::getTemplateInstantiationPattern() const { // If it's a variable template specialization, find the template or partial // specialization from which it was instantiated. if (auto *VDTemplSpec = dyn_cast(this)) { auto From = VDTemplSpec->getInstantiatedFrom(); if (auto *VTD = From.dyn_cast()) { while (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) { if (NewVTD->isMemberSpecialization()) break; VTD = NewVTD; } return getDefinitionOrSelf(VTD->getTemplatedDecl()); } if (auto *VTPSD = From.dyn_cast()) { while (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) { if (NewVTPSD->isMemberSpecialization()) break; VTPSD = NewVTPSD; } return getDefinitionOrSelf(VTPSD); } } if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { VarDecl *VD = getInstantiatedFromStaticDataMember(); while (auto *NewVD = VD->getInstantiatedFromStaticDataMember()) VD = NewVD; return getDefinitionOrSelf(VD); } } if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) { while (VarTemplate->getInstantiatedFromMemberTemplate()) { if (VarTemplate->isMemberSpecialization()) break; VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate(); } return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); } return nullptr; } VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast(MSI->getInstantiatedFrom()); return nullptr; } TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { if (const auto *Spec = dyn_cast(this)) return Spec->getSpecializationKind(); if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getTemplateSpecializationKind(); return TSK_Undeclared; } SourceLocation VarDecl::getPointOfInstantiation() const { if (const auto *Spec = dyn_cast(this)) return Spec->getPointOfInstantiation(); if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getPointOfInstantiation(); return SourceLocation(); } VarTemplateDecl *VarDecl::getDescribedVarTemplate() const { return getASTContext().getTemplateOrSpecializationInfo(this) .dyn_cast(); } void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) { getASTContext().setTemplateOrSpecializationInfo(this, Template); } MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { if (isStaticDataMember()) // FIXME: Remove ? // return getASTContext().getInstantiatedFromStaticDataMember(this); return getASTContext().getTemplateOrSpecializationInfo(this) .dyn_cast(); return nullptr; } void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation) { assert((isa(this) || getMemberSpecializationInfo()) && "not a variable or static data member template specialization"); if (VarTemplateSpecializationDecl *Spec = dyn_cast(this)) { Spec->setSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && Spec->getPointOfInstantiation().isInvalid()) Spec->setPointOfInstantiation(PointOfInstantiation); } if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { MSI->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && MSI->getPointOfInstantiation().isInvalid()) MSI->setPointOfInstantiation(PointOfInstantiation); } } void VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD, TemplateSpecializationKind TSK) { assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() && "Previous template or instantiation?"); getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK); } //===----------------------------------------------------------------------===// // ParmVarDecl Implementation //===----------------------------------------------------------------------===// ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) { return new (C, DC) ParmVarDecl(ParmVar, C, DC, StartLoc, IdLoc, Id, T, TInfo, S, DefArg); } QualType ParmVarDecl::getOriginalType() const { TypeSourceInfo *TSI = getTypeSourceInfo(); QualType T = TSI ? TSI->getType() : getType(); if (const auto *DT = dyn_cast(T)) return DT->getOriginalType(); return T; } ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) ParmVarDecl(ParmVar, C, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, SC_None, nullptr); } SourceRange ParmVarDecl::getSourceRange() const { if (!hasInheritedDefaultArg()) { SourceRange ArgRange = getDefaultArgRange(); if (ArgRange.isValid()) return SourceRange(getOuterLocStart(), ArgRange.getEnd()); } // DeclaratorDecl considers the range of postfix types as overlapping with the // declaration name, but this is not the case with parameters in ObjC methods. if (isa(getDeclContext())) return SourceRange(DeclaratorDecl::getLocStart(), getLocation()); return DeclaratorDecl::getSourceRange(); } Expr *ParmVarDecl::getDefaultArg() { assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); assert(!hasUninstantiatedDefaultArg() && "Default argument is not yet instantiated!"); Expr *Arg = getInit(); if (auto *E = dyn_cast_or_null(Arg)) return E->getSubExpr(); return Arg; } void ParmVarDecl::setDefaultArg(Expr *defarg) { ParmVarDeclBits.DefaultArgKind = DAK_Normal; Init = defarg; } SourceRange ParmVarDecl::getDefaultArgRange() const { switch (ParmVarDeclBits.DefaultArgKind) { case DAK_None: case DAK_Unparsed: // Nothing we can do here. return SourceRange(); case DAK_Uninstantiated: return getUninstantiatedDefaultArg()->getSourceRange(); case DAK_Normal: if (const Expr *E = getInit()) return E->getSourceRange(); // Missing an actual expression, may be invalid. return SourceRange(); } llvm_unreachable("Invalid default argument kind."); } void ParmVarDecl::setUninstantiatedDefaultArg(Expr *arg) { ParmVarDeclBits.DefaultArgKind = DAK_Uninstantiated; Init = arg; } Expr *ParmVarDecl::getUninstantiatedDefaultArg() { assert(hasUninstantiatedDefaultArg() && "Wrong kind of initialization expression!"); return cast_or_null(Init.get()); } bool ParmVarDecl::hasDefaultArg() const { // FIXME: We should just return false for DAK_None here once callers are // prepared for the case that we encountered an invalid default argument and // were unable to even build an invalid expression. return hasUnparsedDefaultArg() || hasUninstantiatedDefaultArg() || !Init.isNull(); } bool ParmVarDecl::isParameterPack() const { return isa(getType()); } void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) { getASTContext().setParameterIndex(this, parameterIndex); ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel; } unsigned ParmVarDecl::getParameterIndexLarge() const { return getASTContext().getParameterIndex(this); } //===----------------------------------------------------------------------===// // FunctionDecl Implementation //===----------------------------------------------------------------------===// void FunctionDecl::getNameForDiagnostic( raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs(); if (TemplateArgs) TemplateSpecializationType::PrintTemplateArgumentList( OS, TemplateArgs->asArray(), Policy); } bool FunctionDecl::isVariadic() const { if (const auto *FT = getType()->getAs()) return FT->isVariadic(); return false; } bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { for (auto I : redecls()) { if (I->doesThisDeclarationHaveABody()) { Definition = I; return true; } } return false; } bool FunctionDecl::hasTrivialBody() const { Stmt *S = getBody(); if (!S) { // Since we don't have a body for this function, we don't know if it's // trivial or not. return false; } if (isa(S) && cast(S)->body_empty()) return true; return false; } bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { for (auto I : redecls()) { if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed || I->hasDefiningAttr()) { Definition = I->IsDeleted ? I->getCanonicalDecl() : I; return true; } } return false; } Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { if (!hasBody(Definition)) return nullptr; if (Definition->Body) return Definition->Body.get(getASTContext().getExternalSource()); return nullptr; } void FunctionDecl::setBody(Stmt *B) { Body = B; if (B) EndRangeLoc = B->getLocEnd(); } void FunctionDecl::setPure(bool P) { IsPure = P; if (P) if (auto *Parent = dyn_cast(getDeclContext())) Parent->markedVirtualFunctionPure(); } template static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) { IdentifierInfo *II = ND->getIdentifier(); return II && II->isStr(Str); } bool FunctionDecl::isMain() const { const TranslationUnitDecl *tunit = dyn_cast(getDeclContext()->getRedeclContext()); return tunit && !tunit->getASTContext().getLangOpts().Freestanding && isNamed(this, "main"); } bool FunctionDecl::isMSVCRTEntryPoint() const { const TranslationUnitDecl *TUnit = dyn_cast(getDeclContext()->getRedeclContext()); if (!TUnit) return false; // Even though we aren't really targeting MSVCRT if we are freestanding, // semantic analysis for these functions remains the same. // MSVCRT entry points only exist on MSVCRT targets. if (!TUnit->getASTContext().getTargetInfo().getTriple().isOSMSVCRT()) return false; // Nameless functions like constructors cannot be entry points. if (!getIdentifier()) return false; return llvm::StringSwitch(getName()) .Cases("main", // an ANSI console app "wmain", // a Unicode console App "WinMain", // an ANSI GUI app "wWinMain", // a Unicode GUI app "DllMain", // a DLL true) .Default(false); } bool FunctionDecl::isReservedGlobalPlacementOperator() const { assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName); assert(getDeclName().getCXXOverloadedOperator() == OO_New || getDeclName().getCXXOverloadedOperator() == OO_Delete || getDeclName().getCXXOverloadedOperator() == OO_Array_New || getDeclName().getCXXOverloadedOperator() == OO_Array_Delete); if (!getDeclContext()->getRedeclContext()->isTranslationUnit()) return false; const auto *proto = getType()->castAs(); if (proto->getNumParams() != 2 || proto->isVariadic()) return false; ASTContext &Context = cast(getDeclContext()->getRedeclContext()) ->getASTContext(); // The result type and first argument type are constant across all // these operators. The second argument must be exactly void*. return (proto->getParamType(1).getCanonicalType() == Context.VoidPtrTy); } bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) return false; if (getDeclName().getCXXOverloadedOperator() != OO_New && getDeclName().getCXXOverloadedOperator() != OO_Delete && getDeclName().getCXXOverloadedOperator() != OO_Array_New && getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) return false; if (isa(getDeclContext())) return false; // This can only fail for an invalid 'operator new' declaration. if (!getDeclContext()->getRedeclContext()->isTranslationUnit()) return false; const auto *FPT = getType()->castAs(); if (FPT->getNumParams() == 0 || FPT->getNumParams() > 3 || FPT->isVariadic()) return false; // If this is a single-parameter function, it must be a replaceable global // allocation or deallocation function. if (FPT->getNumParams() == 1) return true; unsigned Params = 1; QualType Ty = FPT->getParamType(Params); ASTContext &Ctx = getASTContext(); auto Consume = [&] { ++Params; Ty = Params < FPT->getNumParams() ? FPT->getParamType(Params) : QualType(); }; // In C++14, the next parameter can be a 'std::size_t' for sized delete. bool IsSizedDelete = false; if (Ctx.getLangOpts().SizedDeallocation && (getDeclName().getCXXOverloadedOperator() == OO_Delete || getDeclName().getCXXOverloadedOperator() == OO_Array_Delete) && Ctx.hasSameType(Ty, Ctx.getSizeType())) { IsSizedDelete = true; Consume(); } // In C++17, the next parameter can be a 'std::align_val_t' for aligned // new/delete. if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT()) Consume(); // Finally, if this is not a sized delete, the final parameter can // be a 'const std::nothrow_t&'. if (!IsSizedDelete && !Ty.isNull() && Ty->isReferenceType()) { Ty = Ty->getPointeeType(); if (Ty.getCVRQualifiers() != Qualifiers::Const) return false; const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); if (RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace()) Consume(); } return Params == FPT->getNumParams(); } LanguageLinkage FunctionDecl::getLanguageLinkage() const { return getDeclLanguageLinkage(*this); } bool FunctionDecl::isExternC() const { return isDeclExternC(*this); } bool FunctionDecl::isInExternCContext() const { return getLexicalDeclContext()->isExternCContext(); } bool FunctionDecl::isInExternCXXContext() const { return getLexicalDeclContext()->isExternCXXContext(); } bool FunctionDecl::isGlobal() const { if (const auto *Method = dyn_cast(this)) return Method->isStatic(); if (getCanonicalDecl()->getStorageClass() == SC_Static) return false; for (const DeclContext *DC = getDeclContext(); DC->isNamespace(); DC = DC->getParent()) { if (const auto *Namespace = cast(DC)) { if (!Namespace->getDeclName()) return false; break; } } return true; } bool FunctionDecl::isNoReturn() const { if (hasAttr() || hasAttr() || hasAttr()) return true; if (auto *FnTy = getType()->getAs()) return FnTy->getNoReturnAttr(); return false; } void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { redeclarable_base::setPreviousDecl(PrevDecl); if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { FunctionTemplateDecl *PrevFunTmpl = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : nullptr; assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); FunTmpl->setPreviousDecl(PrevFunTmpl); } if (PrevDecl && PrevDecl->IsInline) IsInline = true; } FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. /// /// The function corresponds to a built-in function if it is /// declared at translation scope or within an extern "C" block and /// its name matches with the name of a builtin. The returned value /// will be 0 for functions that do not correspond to a builtin, a /// value of type \c Builtin::ID if in the target-independent range /// \c [1,Builtin::First), or a target-specific builtin value. unsigned FunctionDecl::getBuiltinID() const { if (!getIdentifier()) return 0; unsigned BuiltinID = getIdentifier()->getBuiltinID(); if (!BuiltinID) return 0; ASTContext &Context = getASTContext(); if (Context.getLangOpts().CPlusPlus) { const auto *LinkageDecl = dyn_cast(getFirstDecl()->getDeclContext()); // In C++, the first declaration of a builtin is always inside an implicit // extern "C". // FIXME: A recognised library function may not be directly in an extern "C" // declaration, for instance "extern "C" { namespace std { decl } }". if (!LinkageDecl) { if (BuiltinID == Builtin::BI__GetExceptionInfo && Context.getTargetInfo().getCXXABI().isMicrosoft()) return Builtin::BI__GetExceptionInfo; return 0; } if (LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c) return 0; } // If the function is marked "overloadable", it has a different mangled name // and is not the C library function. if (hasAttr()) return 0; if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return BuiltinID; // This function has the name of a known C library // function. Determine whether it actually refers to the C library // function or whether it just has the same name. // If this is a static function, it's not a builtin. if (getStorageClass() == SC_Static) return 0; // OpenCL v1.2 s6.9.f - The library functions defined in // the C99 standard headers are not available. if (Context.getLangOpts().OpenCL && Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return 0; return BuiltinID; } /// getNumParams - 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 FunctionDecl::getNumParams() const { const auto *FPT = getType()->getAs(); return FPT ? FPT->getNumParams() : 0; } void FunctionDecl::setParams(ASTContext &C, ArrayRef NewParamInfo) { assert(!ParamInfo && "Already has param info!"); assert(NewParamInfo.size() == getNumParams() && "Parameter count mismatch!"); // Zero params -> null pointer. if (!NewParamInfo.empty()) { ParamInfo = new (C) ParmVarDecl*[NewParamInfo.size()]; std::copy(NewParamInfo.begin(), NewParamInfo.end(), ParamInfo); } } /// getMinRequiredArguments - 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++) or are parameter packs (C++11). unsigned FunctionDecl::getMinRequiredArguments() const { if (!getASTContext().getLangOpts().CPlusPlus) return getNumParams(); unsigned NumRequiredArgs = 0; for (auto *Param : parameters()) if (!Param->isParameterPack() && !Param->hasDefaultArg()) ++NumRequiredArgs; return NumRequiredArgs; } /// \brief The combination of the extern and inline keywords under MSVC forces /// the function to be required. /// /// Note: This function assumes that we will only get called when isInlined() /// would return true for this FunctionDecl. bool FunctionDecl::isMSExternInline() const { assert(isInlined() && "expected to get called on an inlined function!"); const ASTContext &Context = getASTContext(); if (!Context.getTargetInfo().getCXXABI().isMicrosoft() && !hasAttr()) return false; for (const FunctionDecl *FD = getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern) return true; return false; } static bool redeclForcesDefMSVC(const FunctionDecl *Redecl) { if (Redecl->getStorageClass() != SC_Extern) return false; for (const FunctionDecl *FD = Redecl->getPreviousDecl(); FD; FD = FD->getPreviousDecl()) if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern) return false; return true; } static bool RedeclForcesDefC99(const FunctionDecl *Redecl) { // Only consider file-scope declarations in this test. if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) return false; // Only consider explicit declarations; the presence of a builtin for a // libcall shouldn't affect whether a definition is externally visible. if (Redecl->isImplicit()) return false; if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == SC_Extern) return true; // Not an inline definition return false; } /// \brief For a function declaration in C or C++, determine whether this /// declaration causes the definition to be externally visible. /// /// For instance, this determines if adding the current declaration to the set /// of redeclarations of the given functions causes /// isInlineDefinitionExternallyVisible to change from false to true. bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { assert(!doesThisDeclarationHaveABody() && "Must have a declaration without a body."); ASTContext &Context = getASTContext(); if (Context.getLangOpts().MSVCCompat) { const FunctionDecl *Definition; if (hasBody(Definition) && Definition->isInlined() && redeclForcesDefMSVC(this)) return true; } if (Context.getLangOpts().GNUInline || hasAttr()) { // With GNU inlining, a declaration with 'inline' but not 'extern', forces // an externally visible definition. // // FIXME: What happens if gnu_inline gets added on after the first // declaration? if (!isInlineSpecified() || getStorageClass() == SC_Extern) return false; const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { FoundBody |= Prev->Body.isValid(); if (Prev->Body) { // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then it is always externally visible. if (!Prev->isInlineSpecified() || Prev->getStorageClass() != SC_Extern) return false; } else if (Prev->isInlineSpecified() && Prev->getStorageClass() != SC_Extern) { return false; } } return FoundBody; } if (Context.getLangOpts().CPlusPlus) return false; // C99 6.7.4p6: // [...] If all of the file scope declarations for a function in a // translation unit include the inline function specifier without extern, // then the definition in that translation unit is an inline definition. if (isInlineSpecified() && getStorageClass() != SC_Extern) return false; const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { FoundBody |= Prev->Body.isValid(); if (RedeclForcesDefC99(Prev)) return false; } return FoundBody; } SourceRange FunctionDecl::getReturnTypeSourceRange() const { const TypeSourceInfo *TSI = getTypeSourceInfo(); if (!TSI) return SourceRange(); FunctionTypeLoc FTL = TSI->getTypeLoc().IgnoreParens().getAs(); if (!FTL) return SourceRange(); // Skip self-referential return types. const SourceManager &SM = getASTContext().getSourceManager(); SourceRange RTRange = FTL.getReturnLoc().getSourceRange(); SourceLocation Boundary = getNameInfo().getLocStart(); if (RTRange.isInvalid() || Boundary.isInvalid() || !SM.isBeforeInTranslationUnit(RTRange.getEnd(), Boundary)) return SourceRange(); return RTRange; } SourceRange FunctionDecl::getExceptionSpecSourceRange() const { const TypeSourceInfo *TSI = getTypeSourceInfo(); if (!TSI) return SourceRange(); FunctionTypeLoc FTL = TSI->getTypeLoc().IgnoreParens().getAs(); if (!FTL) return SourceRange(); return FTL.getExceptionSpecRange(); } const Attr *FunctionDecl::getUnusedResultAttr() const { QualType RetType = getReturnType(); if (RetType->isRecordType()) { if (const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl()) { if (const auto *R = Ret->getAttr()) return R; } } else if (const auto *ET = RetType->getAs()) { if (const EnumDecl *ED = ET->getDecl()) { if (const auto *R = ED->getAttr()) return R; } } return getAttr(); } /// \brief For an inline function definition in C, or for a gnu_inline function /// in C++, determine whether the definition will be externally visible. /// /// Inline function definitions are always available for inlining optimizations. /// However, depending on the language dialect, declaration specifiers, and /// attributes, the definition of an inline function may or may not be /// "externally" visible to other translation units in the program. /// /// In C99, inline definitions are not externally visible by default. However, /// if even one of the global-scope declarations is marked "extern inline", the /// inline definition becomes externally visible (C99 6.7.4p6). /// /// In GNU89 mode, or if the gnu_inline attribute is attached to the function /// definition, we use the GNU semantics for inline, which are nearly the /// opposite of C99 semantics. In particular, "inline" by itself will create /// an externally visible symbol, but "extern inline" will not create an /// externally visible symbol. bool FunctionDecl::isInlineDefinitionExternallyVisible() const { assert((doesThisDeclarationHaveABody() || willHaveBody()) && "Must be a function definition"); assert(isInlined() && "Function must be inline"); ASTContext &Context = getASTContext(); if (Context.getLangOpts().GNUInline || hasAttr()) { // Note: If you change the logic here, please change // doesDeclarationForceExternallyVisibleDefinition as well. // // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then this inline definition is // externally visible. if (!(isInlineSpecified() && getStorageClass() == SC_Extern)) return true; // If any declaration is 'inline' but not 'extern', then this definition // is externally visible. for (auto Redecl : redecls()) { if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != SC_Extern) return true; } return false; } // The rest of this function is C-only. assert(!Context.getLangOpts().CPlusPlus && "should not use C inline rules in C++"); // C99 6.7.4p6: // [...] If all of the file scope declarations for a function in a // translation unit include the inline function specifier without extern, // then the definition in that translation unit is an inline definition. for (auto Redecl : redecls()) { if (RedeclForcesDefC99(Redecl)) return true; } // C99 6.7.4p6: // An inline definition does not provide an external definition for the // function, and does not forbid an external definition in another // translation unit. return false; } /// getOverloadedOperator - Which C++ overloaded operator this /// function represents, if any. OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { if (getDeclName().getNameKind() == DeclarationName::CXXOperatorName) return getDeclName().getCXXOverloadedOperator(); else return OO_None; } /// getLiteralIdentifier - The literal suffix identifier this function /// represents, if any. const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const { if (getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName) return getDeclName().getCXXLiteralIdentifier(); else return nullptr; } FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const { if (TemplateOrSpecialization.isNull()) return TK_NonTemplate; if (TemplateOrSpecialization.is()) return TK_FunctionTemplate; if (TemplateOrSpecialization.is()) return TK_MemberSpecialization; if (TemplateOrSpecialization.is()) return TK_FunctionTemplateSpecialization; if (TemplateOrSpecialization.is ()) return TK_DependentFunctionTemplateSpecialization; llvm_unreachable("Did we miss a TemplateOrSpecialization type?"); } FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) return cast(Info->getInstantiatedFrom()); return nullptr; } MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { return TemplateOrSpecialization.dyn_cast(); } void FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD, TemplateSpecializationKind TSK) { assert(TemplateOrSpecialization.isNull() && "Member function is already a specialization"); MemberSpecializationInfo *Info = new (C) MemberSpecializationInfo(FD, TSK); TemplateOrSpecialization = Info; } FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const { return TemplateOrSpecialization.dyn_cast(); } void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { TemplateOrSpecialization = Template; } bool FunctionDecl::isImplicitlyInstantiable() const { // If the function is invalid, it can't be implicitly instantiated. if (isInvalidDecl()) return false; switch (getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitInstantiationDefinition: return false; case TSK_ImplicitInstantiation: return true; // It is possible to instantiate TSK_ExplicitSpecialization kind // if the FunctionDecl has a class scope specialization pattern. case TSK_ExplicitSpecialization: return getClassScopeSpecializationPattern() != nullptr; case TSK_ExplicitInstantiationDeclaration: // Handled below. break; } // Find the actual template from which we will instantiate. const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); bool HasPattern = false; if (PatternDecl) HasPattern = PatternDecl->hasBody(PatternDecl); // C++0x [temp.explicit]p9: // Except for inline functions, other explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity // to which they refer. if (!HasPattern || !PatternDecl) return true; return PatternDecl->isInlined(); } bool FunctionDecl::isTemplateInstantiation() const { switch (getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: return false; case TSK_ImplicitInstantiation: case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: return true; } llvm_unreachable("All TSK values handled."); } FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { // Handle class scope explicit specialization special case. if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { if (auto *Spec = getClassScopeSpecializationPattern()) return getDefinitionOrSelf(Spec); return nullptr; } // If this is a generic lambda call operator specialization, its // instantiation pattern is always its primary template's pattern // even if its primary template was instantiated from another // member template (which happens with nested generic lambdas). // Since a lambda's call operator's body is transformed eagerly, // we don't have to go hunting for a prototype definition template // (i.e. instantiated-from-member-template) to use as an instantiation // pattern. if (isGenericLambdaCallOperatorSpecialization( dyn_cast(this))) { assert(getPrimaryTemplate() && "not a generic lambda call operator?"); return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl()); } if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { while (Primary->getInstantiatedFromMemberTemplate()) { // If we have hit a point where the user provided a specialization of // this template, we're done looking. if (Primary->isMemberSpecialization()) break; Primary = Primary->getInstantiatedFromMemberTemplate(); } return getDefinitionOrSelf(Primary->getTemplatedDecl()); } if (auto *MFD = getInstantiatedFromMemberFunction()) return getDefinitionOrSelf(MFD); return nullptr; } FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast()) { return Info->Template.getPointer(); } return nullptr; } FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const { return getASTContext().getClassScopeSpecializationPattern(this); } FunctionTemplateSpecializationInfo * FunctionDecl::getTemplateSpecializationInfo() const { return TemplateOrSpecialization .dyn_cast(); } const TemplateArgumentList * FunctionDecl::getTemplateSpecializationArgs() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast()) { return Info->TemplateArguments; } return nullptr; } const ASTTemplateArgumentListInfo * FunctionDecl::getTemplateSpecializationArgsAsWritten() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast()) { return Info->TemplateArgumentsAsWritten; } return nullptr; } void FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, void *InsertPos, TemplateSpecializationKind TSK, const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation PointOfInstantiation) { assert(TSK != TSK_Undeclared && "Must specify the type of function template specialization"); FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization.dyn_cast(); if (!Info) Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten, PointOfInstantiation); TemplateOrSpecialization = Info; Template->addSpecialization(Info, InsertPos); } void FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, const UnresolvedSetImpl &Templates, const TemplateArgumentListInfo &TemplateArgs) { assert(TemplateOrSpecialization.isNull()); DependentFunctionTemplateSpecializationInfo *Info = DependentFunctionTemplateSpecializationInfo::Create(Context, Templates, TemplateArgs); TemplateOrSpecialization = Info; } DependentFunctionTemplateSpecializationInfo * FunctionDecl::getDependentSpecializationInfo() const { return TemplateOrSpecialization .dyn_cast(); } DependentFunctionTemplateSpecializationInfo * DependentFunctionTemplateSpecializationInfo::Create( ASTContext &Context, const UnresolvedSetImpl &Ts, const TemplateArgumentListInfo &TArgs) { void *Buffer = Context.Allocate( totalSizeToAlloc( TArgs.size(), Ts.size())); return new (Buffer) DependentFunctionTemplateSpecializationInfo(Ts, TArgs); } DependentFunctionTemplateSpecializationInfo:: DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, const TemplateArgumentListInfo &TArgs) : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { NumTemplates = Ts.size(); NumArgs = TArgs.size(); FunctionTemplateDecl **TsArray = getTrailingObjects(); for (unsigned I = 0, E = Ts.size(); I != E; ++I) TsArray[I] = cast(Ts[I]->getUnderlyingDecl()); TemplateArgumentLoc *ArgsArray = getTrailingObjects(); for (unsigned I = 0, E = TArgs.size(); I != E; ++I) new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]); } TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast(); if (FTSInfo) return FTSInfo->getTemplateSpecializationKind(); MemberSpecializationInfo *MSInfo = TemplateOrSpecialization.dyn_cast(); if (MSInfo) return MSInfo->getTemplateSpecializationKind(); return TSK_Undeclared; } void FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation) { if (FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast< FunctionTemplateSpecializationInfo*>()) { FTSInfo->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && FTSInfo->getPointOfInstantiation().isInvalid()) FTSInfo->setPointOfInstantiation(PointOfInstantiation); } else if (MemberSpecializationInfo *MSInfo = TemplateOrSpecialization.dyn_cast()) { MSInfo->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && MSInfo->getPointOfInstantiation().isInvalid()) MSInfo->setPointOfInstantiation(PointOfInstantiation); } else llvm_unreachable("Function cannot have a template specialization kind"); } SourceLocation FunctionDecl::getPointOfInstantiation() const { if (FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast< FunctionTemplateSpecializationInfo*>()) return FTSInfo->getPointOfInstantiation(); else if (MemberSpecializationInfo *MSInfo = TemplateOrSpecialization.dyn_cast()) return MSInfo->getPointOfInstantiation(); return SourceLocation(); } bool FunctionDecl::isOutOfLine() const { if (Decl::isOutOfLine()) return true; // If this function was instantiated from a member function of a // class template, check whether that member function was defined out-of-line. if (FunctionDecl *FD = getInstantiatedFromMemberFunction()) { const FunctionDecl *Definition; if (FD->hasBody(Definition)) return Definition->isOutOfLine(); } // If this function was instantiated from a function template, // check whether that function template was defined out-of-line. if (FunctionTemplateDecl *FunTmpl = getPrimaryTemplate()) { const FunctionDecl *Definition; if (FunTmpl->getTemplatedDecl()->hasBody(Definition)) return Definition->isOutOfLine(); } return false; } SourceRange FunctionDecl::getSourceRange() const { return SourceRange(getOuterLocStart(), EndRangeLoc); } unsigned FunctionDecl::getMemoryFunctionKind() const { IdentifierInfo *FnInfo = getIdentifier(); if (!FnInfo) return 0; // Builtin handling. switch (getBuiltinID()) { case Builtin::BI__builtin_memset: case Builtin::BI__builtin___memset_chk: case Builtin::BImemset: return Builtin::BImemset; case Builtin::BI__builtin_memcpy: case Builtin::BI__builtin___memcpy_chk: case Builtin::BImemcpy: return Builtin::BImemcpy; case Builtin::BI__builtin_memmove: case Builtin::BI__builtin___memmove_chk: case Builtin::BImemmove: return Builtin::BImemmove; case Builtin::BIstrlcpy: case Builtin::BI__builtin___strlcpy_chk: return Builtin::BIstrlcpy; case Builtin::BIstrlcat: case Builtin::BI__builtin___strlcat_chk: return Builtin::BIstrlcat; case Builtin::BI__builtin_memcmp: case Builtin::BImemcmp: return Builtin::BImemcmp; case Builtin::BI__builtin_strncpy: case Builtin::BI__builtin___strncpy_chk: case Builtin::BIstrncpy: return Builtin::BIstrncpy; case Builtin::BI__builtin_strncmp: case Builtin::BIstrncmp: return Builtin::BIstrncmp; case Builtin::BI__builtin_strncasecmp: case Builtin::BIstrncasecmp: return Builtin::BIstrncasecmp; case Builtin::BI__builtin_strncat: case Builtin::BI__builtin___strncat_chk: case Builtin::BIstrncat: return Builtin::BIstrncat; case Builtin::BI__builtin_strndup: case Builtin::BIstrndup: return Builtin::BIstrndup; case Builtin::BI__builtin_strlen: case Builtin::BIstrlen: return Builtin::BIstrlen; case Builtin::BI__builtin_bzero: case Builtin::BIbzero: return Builtin::BIbzero; default: if (isExternC()) { if (FnInfo->isStr("memset")) return Builtin::BImemset; else if (FnInfo->isStr("memcpy")) return Builtin::BImemcpy; else if (FnInfo->isStr("memmove")) return Builtin::BImemmove; else if (FnInfo->isStr("memcmp")) return Builtin::BImemcmp; else if (FnInfo->isStr("strncpy")) return Builtin::BIstrncpy; else if (FnInfo->isStr("strncmp")) return Builtin::BIstrncmp; else if (FnInfo->isStr("strncasecmp")) return Builtin::BIstrncasecmp; else if (FnInfo->isStr("strncat")) return Builtin::BIstrncat; else if (FnInfo->isStr("strndup")) return Builtin::BIstrndup; else if (FnInfo->isStr("strlen")) return Builtin::BIstrlen; else if (FnInfo->isStr("bzero")) return Builtin::BIbzero; } break; } return 0; } //===----------------------------------------------------------------------===// // FieldDecl Implementation //===----------------------------------------------------------------------===// FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle) { return new (C, DC) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, BW, Mutable, InitStyle); } FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) FieldDecl(Field, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, nullptr, false, ICIS_NoInit); } bool FieldDecl::isAnonymousStructOrUnion() const { if (!isImplicit() || getDeclName()) return false; if (const auto *Record = getType()->getAs()) return Record->getDecl()->isAnonymousStructOrUnion(); return false; } unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { assert(isBitField() && "not a bitfield"); auto *BitWidth = static_cast(InitStorage.getPointer()); return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue(); } unsigned FieldDecl::getFieldIndex() const { const FieldDecl *Canonical = getCanonicalDecl(); if (Canonical != this) return Canonical->getFieldIndex(); if (CachedFieldIndex) return CachedFieldIndex - 1; unsigned Index = 0; const RecordDecl *RD = getParent(); for (auto *Field : RD->fields()) { Field->getCanonicalDecl()->CachedFieldIndex = Index + 1; ++Index; } assert(CachedFieldIndex && "failed to find field in parent"); return CachedFieldIndex - 1; } SourceRange FieldDecl::getSourceRange() const { switch (InitStorage.getInt()) { // All three of these cases store an optional Expr*. case ISK_BitWidthOrNothing: case ISK_InClassCopyInit: case ISK_InClassListInit: if (const auto *E = static_cast(InitStorage.getPointer())) return SourceRange(getInnerLocStart(), E->getLocEnd()); // FALLTHROUGH case ISK_CapturedVLAType: return DeclaratorDecl::getSourceRange(); } llvm_unreachable("bad init storage kind"); } void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) { assert((getParent()->isLambda() || getParent()->isCapturedRecord()) && "capturing type in non-lambda or captured record."); assert(InitStorage.getInt() == ISK_BitWidthOrNothing && InitStorage.getPointer() == nullptr && "bit width, initializer or captured type already set"); InitStorage.setPointerAndInt(const_cast(VLAType), ISK_CapturedVLAType); } //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// SourceLocation TagDecl::getOuterLocStart() const { return getTemplateOrInnerLocStart(this); } SourceRange TagDecl::getSourceRange() const { SourceLocation RBraceLoc = BraceRange.getEnd(); SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation(); return SourceRange(getOuterLocStart(), E); } TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); } void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { TypedefNameDeclOrQualifier = TDD; if (const Type *T = getTypeForDecl()) { (void)T; assert(T->isLinkageValid()); } assert(isLinkageValid()); } void TagDecl::startDefinition() { IsBeingDefined = true; if (auto *D = dyn_cast(this)) { struct CXXRecordDecl::DefinitionData *Data = new (getASTContext()) struct CXXRecordDecl::DefinitionData(D); for (auto I : redecls()) cast(I)->DefinitionData = Data; } } void TagDecl::completeDefinition() { assert((!isa(this) || cast(this)->hasDefinition()) && "definition completed but not started"); IsCompleteDefinition = true; IsBeingDefined = false; if (ASTMutationListener *L = getASTMutationListener()) L->CompletedTagDefinition(this); } TagDecl *TagDecl::getDefinition() const { if (isCompleteDefinition()) return const_cast(this); // If it's possible for us to have an out-of-date definition, check now. if (MayHaveOutOfDateDef) { if (IdentifierInfo *II = getIdentifier()) { if (II->isOutOfDate()) { updateOutOfDate(*II); } } } if (const auto *CXXRD = dyn_cast(this)) return CXXRD->getDefinition(); for (auto R : redecls()) if (R->isCompleteDefinition()) return R; return nullptr; } void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { if (QualifierLoc) { // Make sure the extended qualifier info is allocated. if (!hasExtInfo()) TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; // Set qualifier info. getExtInfo()->QualifierLoc = QualifierLoc; } else { // Here Qualifier == 0, i.e., we are removing the qualifier (if any). if (hasExtInfo()) { if (getExtInfo()->NumTemplParamLists == 0) { getASTContext().Deallocate(getExtInfo()); TypedefNameDeclOrQualifier = (TypedefNameDecl *)nullptr; } else getExtInfo()->QualifierLoc = QualifierLoc; } } } void TagDecl::setTemplateParameterListsInfo( ASTContext &Context, ArrayRef TPLists) { assert(!TPLists.empty()); // Make sure the extended decl info is allocated. if (!hasExtInfo()) // Allocate external info struct. TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; // Set the template parameter lists info. getExtInfo()->setTemplateParameterListsInfo(Context, TPLists); } //===----------------------------------------------------------------------===// // EnumDecl Implementation //===----------------------------------------------------------------------===// void EnumDecl::anchor() { } EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, bool IsScoped, bool IsScopedUsingClassTag, bool IsFixed) { auto *Enum = new (C, DC) EnumDecl(C, DC, StartLoc, IdLoc, Id, PrevDecl, IsScoped, IsScopedUsingClassTag, IsFixed); Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules; C.getTypeDeclType(Enum, PrevDecl); return Enum; } EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) { EnumDecl *Enum = new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr, false, false, false); Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules; return Enum; } SourceRange EnumDecl::getIntegerTypeRange() const { if (const TypeSourceInfo *TI = getIntegerTypeSourceInfo()) return TI->getTypeLoc().getSourceRange(); return SourceRange(); } void EnumDecl::completeDefinition(QualType NewType, QualType NewPromotionType, unsigned NumPositiveBits, unsigned NumNegativeBits) { assert(!isCompleteDefinition() && "Cannot redefine enums!"); if (!IntegerType) IntegerType = NewType.getTypePtr(); PromotionType = NewPromotionType; setNumPositiveBits(NumPositiveBits); setNumNegativeBits(NumNegativeBits); TagDecl::completeDefinition(); } bool EnumDecl::isClosed() const { if (const auto *A = getAttr()) return A->getExtensibility() == EnumExtensibilityAttr::Closed; return true; } bool EnumDecl::isClosedFlag() const { return isClosed() && hasAttr(); } bool EnumDecl::isClosedNonFlag() const { return isClosed() && !hasAttr(); } TemplateSpecializationKind EnumDecl::getTemplateSpecializationKind() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getTemplateSpecializationKind(); return TSK_Undeclared; } void EnumDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation) { MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); assert(MSI && "Not an instantiated member enumeration?"); MSI->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && MSI->getPointOfInstantiation().isInvalid()) MSI->setPointOfInstantiation(PointOfInstantiation); } EnumDecl *EnumDecl::getTemplateInstantiationPattern() const { if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { EnumDecl *ED = getInstantiatedFromMemberEnum(); while (auto *NewED = ED->getInstantiatedFromMemberEnum()) ED = NewED; return getDefinitionOrSelf(ED); } } assert(!isTemplateInstantiation(getTemplateSpecializationKind()) && "couldn't find pattern for enum instantiation"); return nullptr; } EnumDecl *EnumDecl::getInstantiatedFromMemberEnum() const { if (SpecializationInfo) return cast(SpecializationInfo->getInstantiatedFrom()); return nullptr; } void EnumDecl::setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, TemplateSpecializationKind TSK) { assert(!SpecializationInfo && "Member enum is already a specialization"); SpecializationInfo = new (C) MemberSpecializationInfo(ED, TSK); } //===----------------------------------------------------------------------===// // RecordDecl Implementation //===----------------------------------------------------------------------===// RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, RecordDecl *PrevDecl) : TagDecl(DK, TK, C, DC, IdLoc, Id, PrevDecl, StartLoc) { HasFlexibleArrayMember = false; AnonymousStructOrUnion = false; HasObjectMember = false; HasVolatileMember = false; LoadedFieldsFromExternalStorage = false; assert(classof(static_cast(this)) && "Invalid Kind!"); } RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, RecordDecl* PrevDecl) { RecordDecl *R = new (C, DC) RecordDecl(Record, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); R->MayHaveOutOfDateDef = C.getLangOpts().Modules; C.getTypeDeclType(R, PrevDecl); return R; } RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { RecordDecl *R = new (C, ID) RecordDecl(Record, TTK_Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); R->MayHaveOutOfDateDef = C.getLangOpts().Modules; return R; } bool RecordDecl::isInjectedClassName() const { return isImplicit() && getDeclName() && getDeclContext()->isRecord() && cast(getDeclContext())->getDeclName() == getDeclName(); } bool RecordDecl::isLambda() const { if (auto RD = dyn_cast(this)) return RD->isLambda(); return false; } bool RecordDecl::isCapturedRecord() const { return hasAttr(); } void RecordDecl::setCapturedRecord() { addAttr(CapturedRecordAttr::CreateImplicit(getASTContext())); } RecordDecl::field_iterator RecordDecl::field_begin() const { if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage) LoadFieldsFromExternalStorage(); return field_iterator(decl_iterator(FirstDecl)); } /// completeDefinition - Notes that the definition of this type is now /// complete. void RecordDecl::completeDefinition() { assert(!isCompleteDefinition() && "Cannot redefine record!"); TagDecl::completeDefinition(); } /// isMsStruct - Get whether or not this record uses ms_struct layout. /// This which can be turned on with an attribute, pragma, or the /// -mms-bitfields command-line option. bool RecordDecl::isMsStruct(const ASTContext &C) const { return hasAttr() || C.getLangOpts().MSBitfields == 1; } void RecordDecl::LoadFieldsFromExternalStorage() const { ExternalASTSource *Source = getASTContext().getExternalSource(); assert(hasExternalLexicalStorage() && Source && "No external storage?"); // Notify that we have a RecordDecl doing some initialization. ExternalASTSource::Deserializing TheFields(Source); SmallVector Decls; LoadedFieldsFromExternalStorage = true; Source->FindExternalLexicalDecls(this, [](Decl::Kind K) { return FieldDecl::classofKind(K) || IndirectFieldDecl::classofKind(K); }, Decls); #ifndef NDEBUG // Check that all decls we got were FieldDecls. for (unsigned i=0, e=Decls.size(); i != e; ++i) assert(isa(Decls[i]) || isa(Decls[i])); #endif if (Decls.empty()) return; std::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls, /*FieldsAlreadyLoaded=*/false); } bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const { ASTContext &Context = getASTContext(); if (!Context.getLangOpts().Sanitize.hasOneOf( SanitizerKind::Address | SanitizerKind::KernelAddress) || !Context.getLangOpts().SanitizeAddressFieldPadding) return false; const auto &Blacklist = Context.getSanitizerBlacklist(); const auto *CXXRD = dyn_cast(this); // We may be able to relax some of these requirements. int ReasonToReject = -1; if (!CXXRD || CXXRD->isExternCContext()) ReasonToReject = 0; // is not C++. else if (CXXRD->hasAttr()) ReasonToReject = 1; // is packed. else if (CXXRD->isUnion()) ReasonToReject = 2; // is a union. else if (CXXRD->isTriviallyCopyable()) ReasonToReject = 3; // is trivially copyable. else if (CXXRD->hasTrivialDestructor()) ReasonToReject = 4; // has trivial destructor. else if (CXXRD->isStandardLayout()) ReasonToReject = 5; // is standard layout. else if (Blacklist.isBlacklistedLocation(getLocation(), "field-padding")) ReasonToReject = 6; // is in a blacklisted file. else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(), "field-padding")) ReasonToReject = 7; // is blacklisted. if (EmitRemark) { if (ReasonToReject >= 0) Context.getDiagnostics().Report( getLocation(), diag::remark_sanitize_address_insert_extra_padding_rejected) << getQualifiedNameAsString() << ReasonToReject; else Context.getDiagnostics().Report( getLocation(), diag::remark_sanitize_address_insert_extra_padding_accepted) << getQualifiedNameAsString(); } return ReasonToReject < 0; } const FieldDecl *RecordDecl::findFirstNamedDataMember() const { for (const auto *I : fields()) { if (I->getIdentifier()) return I; if (const auto *RT = I->getType()->getAs()) if (const FieldDecl *NamedDataMember = RT->getDecl()->findFirstNamedDataMember()) return NamedDataMember; } // We didn't find a named data member. return nullptr; } //===----------------------------------------------------------------------===// // BlockDecl Implementation //===----------------------------------------------------------------------===// void BlockDecl::setParams(ArrayRef NewParamInfo) { assert(!ParamInfo && "Already has param info!"); // Zero params -> null pointer. if (!NewParamInfo.empty()) { NumParams = NewParamInfo.size(); ParamInfo = new (getASTContext()) ParmVarDecl*[NewParamInfo.size()]; std::copy(NewParamInfo.begin(), NewParamInfo.end(), ParamInfo); } } void BlockDecl::setCaptures(ASTContext &Context, ArrayRef Captures, bool CapturesCXXThis) { this->CapturesCXXThis = CapturesCXXThis; this->NumCaptures = Captures.size(); if (Captures.empty()) { this->Captures = nullptr; return; } this->Captures = Captures.copy(Context).data(); } bool BlockDecl::capturesVariable(const VarDecl *variable) const { for (const auto &I : captures()) // Only auto vars can be captured, so no redeclaration worries. if (I.getVariable() == variable) return true; return false; } SourceRange BlockDecl::getSourceRange() const { return SourceRange(getLocation(), Body? Body->getLocEnd() : getLocation()); } //===----------------------------------------------------------------------===// // Other Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// void TranslationUnitDecl::anchor() { } TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { return new (C, (DeclContext *)nullptr) TranslationUnitDecl(C); } void PragmaCommentDecl::anchor() { } PragmaCommentDecl *PragmaCommentDecl::Create(const ASTContext &C, TranslationUnitDecl *DC, SourceLocation CommentLoc, PragmaMSCommentKind CommentKind, StringRef Arg) { PragmaCommentDecl *PCD = new (C, DC, additionalSizeToAlloc(Arg.size() + 1)) PragmaCommentDecl(DC, CommentLoc, CommentKind); memcpy(PCD->getTrailingObjects(), Arg.data(), Arg.size()); PCD->getTrailingObjects()[Arg.size()] = '\0'; return PCD; } PragmaCommentDecl *PragmaCommentDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned ArgSize) { return new (C, ID, additionalSizeToAlloc(ArgSize + 1)) PragmaCommentDecl(nullptr, SourceLocation(), PCK_Unknown); } void PragmaDetectMismatchDecl::anchor() { } PragmaDetectMismatchDecl * PragmaDetectMismatchDecl::Create(const ASTContext &C, TranslationUnitDecl *DC, SourceLocation Loc, StringRef Name, StringRef Value) { size_t ValueStart = Name.size() + 1; PragmaDetectMismatchDecl *PDMD = new (C, DC, additionalSizeToAlloc(ValueStart + Value.size() + 1)) PragmaDetectMismatchDecl(DC, Loc, ValueStart); memcpy(PDMD->getTrailingObjects(), Name.data(), Name.size()); PDMD->getTrailingObjects()[Name.size()] = '\0'; memcpy(PDMD->getTrailingObjects() + ValueStart, Value.data(), Value.size()); PDMD->getTrailingObjects()[ValueStart + Value.size()] = '\0'; return PDMD; } PragmaDetectMismatchDecl * PragmaDetectMismatchDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned NameValueSize) { return new (C, ID, additionalSizeToAlloc(NameValueSize + 1)) PragmaDetectMismatchDecl(nullptr, SourceLocation(), 0); } void ExternCContextDecl::anchor() { } ExternCContextDecl *ExternCContextDecl::Create(const ASTContext &C, TranslationUnitDecl *DC) { return new (C, DC) ExternCContextDecl(DC); } void LabelDecl::anchor() { } LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II) { return new (C, DC) LabelDecl(DC, IdentL, II, nullptr, IdentL); } LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II, SourceLocation GnuLabelL) { assert(GnuLabelL != IdentL && "Use this only for GNU local labels"); return new (C, DC) LabelDecl(DC, IdentL, II, nullptr, GnuLabelL); } LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) LabelDecl(nullptr, SourceLocation(), nullptr, nullptr, SourceLocation()); } void LabelDecl::setMSAsmLabel(StringRef Name) { char *Buffer = new (getASTContext(), 1) char[Name.size() + 1]; memcpy(Buffer, Name.data(), Name.size()); Buffer[Name.size()] = '\0'; MSAsmName = Buffer; } void ValueDecl::anchor() { } bool ValueDecl::isWeak() const { for (const auto *I : attrs()) if (isa(I) || isa(I)) return true; return isWeakImported(); } void ImplicitParamDecl::anchor() { } ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType Type) { return new (C, DC) ImplicitParamDecl(C, DC, IdLoc, Id, Type); } ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) ImplicitParamDecl(C, nullptr, SourceLocation(), nullptr, QualType()); } FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool isInlineSpecified, bool hasWrittenPrototype, bool isConstexprSpecified) { FunctionDecl *New = new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, isInlineSpecified, isConstexprSpecified); New->HasWrittenPrototype = hasWrittenPrototype; return New; } FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, SC_None, false, false); } BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { return new (C, DC) BlockDecl(DC, L); } BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) BlockDecl(nullptr, SourceLocation()); } CapturedDecl::CapturedDecl(DeclContext *DC, unsigned NumParams) : Decl(Captured, DC, SourceLocation()), DeclContext(Captured), NumParams(NumParams), ContextParam(0), BodyAndNothrow(nullptr, false) {} CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC, unsigned NumParams) { return new (C, DC, additionalSizeToAlloc(NumParams)) CapturedDecl(DC, NumParams); } CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned NumParams) { return new (C, ID, additionalSizeToAlloc(NumParams)) CapturedDecl(nullptr, NumParams); } Stmt *CapturedDecl::getBody() const { return BodyAndNothrow.getPointer(); } void CapturedDecl::setBody(Stmt *B) { BodyAndNothrow.setPointer(B); } bool CapturedDecl::isNothrow() const { return BodyAndNothrow.getInt(); } void CapturedDecl::setNothrow(bool Nothrow) { BodyAndNothrow.setInt(Nothrow); } EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E, const llvm::APSInt &V) { return new (C, CD) EnumConstantDecl(CD, L, Id, T, E, V); } EnumConstantDecl * EnumConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) EnumConstantDecl(nullptr, SourceLocation(), nullptr, QualType(), nullptr, llvm::APSInt()); } void IndirectFieldDecl::anchor() { } IndirectFieldDecl::IndirectFieldDecl(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, MutableArrayRef CH) : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH.data()), ChainingSize(CH.size()) { // In C++, indirect field declarations conflict with tag declarations in the // same scope, so add them to IDNS_Tag so that tag redeclaration finds them. if (C.getLangOpts().CPlusPlus) IdentifierNamespace |= IDNS_Tag; } IndirectFieldDecl * IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, llvm::MutableArrayRef CH) { return new (C, DC) IndirectFieldDecl(C, DC, L, Id, T, CH); } IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) IndirectFieldDecl(C, nullptr, SourceLocation(), DeclarationName(), QualType(), None); } SourceRange EnumConstantDecl::getSourceRange() const { SourceLocation End = getLocation(); if (Init) End = Init->getLocEnd(); return SourceRange(getLocation(), End); } void TypeDecl::anchor() { } TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) { return new (C, DC) TypedefDecl(C, DC, StartLoc, IdLoc, Id, TInfo); } void TypedefNameDecl::anchor() { } TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const { if (auto *TT = getTypeSourceInfo()->getType()->getAs()) { auto *OwningTypedef = TT->getDecl()->getTypedefNameForAnonDecl(); auto *ThisTypedef = this; if (AnyRedecl && OwningTypedef) { OwningTypedef = OwningTypedef->getCanonicalDecl(); ThisTypedef = ThisTypedef->getCanonicalDecl(); } if (OwningTypedef == ThisTypedef) return TT->getDecl(); } return nullptr; } bool TypedefNameDecl::isTransparentTagSlow() const { auto determineIsTransparent = [&]() { if (auto *TT = getUnderlyingType()->getAs()) { if (auto *TD = TT->getDecl()) { if (TD->getName() != getName()) return false; SourceLocation TTLoc = getLocation(); SourceLocation TDLoc = TD->getLocation(); if (!TTLoc.isMacroID() || !TDLoc.isMacroID()) return false; SourceManager &SM = getASTContext().getSourceManager(); return SM.getSpellingLoc(TTLoc) == SM.getSpellingLoc(TDLoc); } } return false; }; bool isTransparent = determineIsTransparent(); CacheIsTransparentTag = 1; if (isTransparent) CacheIsTransparentTag |= 0x2; return isTransparent; } TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); } TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) { return new (C, DC) TypeAliasDecl(C, DC, StartLoc, IdLoc, Id, TInfo); } TypeAliasDecl *TypeAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) TypeAliasDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); } SourceRange TypedefDecl::getSourceRange() const { SourceLocation RangeEnd = getLocation(); if (TypeSourceInfo *TInfo = getTypeSourceInfo()) { if (typeIsPostfix(TInfo->getType())) RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); } return SourceRange(getLocStart(), RangeEnd); } SourceRange TypeAliasDecl::getSourceRange() const { SourceLocation RangeEnd = getLocStart(); if (TypeSourceInfo *TInfo = getTypeSourceInfo()) RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); return SourceRange(getLocStart(), RangeEnd); } void FileScopeAsmDecl::anchor() { } FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, StringLiteral *Str, SourceLocation AsmLoc, SourceLocation RParenLoc) { return new (C, DC) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc); } FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) FileScopeAsmDecl(nullptr, nullptr, SourceLocation(), SourceLocation()); } void EmptyDecl::anchor() {} EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { return new (C, DC) EmptyDecl(DC, L); } EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) EmptyDecl(nullptr, SourceLocation()); } //===----------------------------------------------------------------------===// // ImportDecl Implementation //===----------------------------------------------------------------------===// /// \brief Retrieve the number of module identifiers needed to name the given /// module. static unsigned getNumModuleIdentifiers(Module *Mod) { unsigned Result = 1; while (Mod->Parent) { Mod = Mod->Parent; ++Result; } return Result; } ImportDecl::ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, ArrayRef IdentifierLocs) : Decl(Import, DC, StartLoc), ImportedAndComplete(Imported, true), NextLocalImport() { assert(getNumModuleIdentifiers(Imported) == IdentifierLocs.size()); auto *StoredLocs = getTrailingObjects(); std::uninitialized_copy(IdentifierLocs.begin(), IdentifierLocs.end(), StoredLocs); } ImportDecl::ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, SourceLocation EndLoc) : Decl(Import, DC, StartLoc), ImportedAndComplete(Imported, false), NextLocalImport() { *getTrailingObjects() = EndLoc; } ImportDecl *ImportDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, Module *Imported, ArrayRef IdentifierLocs) { return new (C, DC, additionalSizeToAlloc(IdentifierLocs.size())) ImportDecl(DC, StartLoc, Imported, IdentifierLocs); } ImportDecl *ImportDecl::CreateImplicit(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, Module *Imported, SourceLocation EndLoc) { ImportDecl *Import = new (C, DC, additionalSizeToAlloc(1)) ImportDecl(DC, StartLoc, Imported, EndLoc); Import->setImplicit(); return Import; } ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned NumLocations) { return new (C, ID, additionalSizeToAlloc(NumLocations)) ImportDecl(EmptyShell()); } ArrayRef ImportDecl::getIdentifierLocs() const { if (!ImportedAndComplete.getInt()) return None; const auto *StoredLocs = getTrailingObjects(); return llvm::makeArrayRef(StoredLocs, getNumModuleIdentifiers(getImportedModule())); } SourceRange ImportDecl::getSourceRange() const { if (!ImportedAndComplete.getInt()) return SourceRange(getLocation(), *getTrailingObjects()); return SourceRange(getLocation(), getIdentifierLocs().back()); } //===----------------------------------------------------------------------===// // ExportDecl Implementation //===----------------------------------------------------------------------===// void ExportDecl::anchor() {} ExportDecl *ExportDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation ExportLoc) { return new (C, DC) ExportDecl(DC, ExportLoc); } ExportDecl *ExportDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) ExportDecl(nullptr, SourceLocation()); } Index: vendor/clang/dist/lib/AST/DeclBase.cpp =================================================================== --- vendor/clang/dist/lib/AST/DeclBase.cpp (revision 318415) +++ vendor/clang/dist/lib/AST/DeclBase.cpp (revision 318416) @@ -1,1828 +1,1832 @@ //===--- DeclBase.cpp - Declaration AST Node Implementation ---------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Decl and DeclContext classes. // //===----------------------------------------------------------------------===// #include "clang/AST/DeclBase.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DependentDiagnostic.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Support/raw_ostream.h" #include using namespace clang; //===----------------------------------------------------------------------===// // Statistics //===----------------------------------------------------------------------===// #define DECL(DERIVED, BASE) static int n##DERIVED##s = 0; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" void Decl::updateOutOfDate(IdentifierInfo &II) const { getASTContext().getExternalSource()->updateOutOfDateIdentifier(II); } #define DECL(DERIVED, BASE) \ static_assert(alignof(Decl) >= alignof(DERIVED##Decl), \ "Alignment sufficient after objects prepended to " #DERIVED); #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" void *Decl::operator new(std::size_t Size, const ASTContext &Context, unsigned ID, std::size_t Extra) { // Allocate an extra 8 bytes worth of storage, which ensures that the // resulting pointer will still be 8-byte aligned. static_assert(sizeof(unsigned) * 2 >= alignof(Decl), "Decl won't be misaligned"); void *Start = Context.Allocate(Size + Extra + 8); void *Result = (char*)Start + 8; unsigned *PrefixPtr = (unsigned *)Result - 2; // Zero out the first 4 bytes; this is used to store the owning module ID. PrefixPtr[0] = 0; // Store the global declaration ID in the second 4 bytes. PrefixPtr[1] = ID; return Result; } void *Decl::operator new(std::size_t Size, const ASTContext &Ctx, DeclContext *Parent, std::size_t Extra) { assert(!Parent || &Parent->getParentASTContext() == &Ctx); // With local visibility enabled, we track the owning module even for local // declarations. - if (Ctx.getLangOpts().ModulesLocalVisibility) { + if (Ctx.getLangOpts().trackLocalOwningModule()) { // Ensure required alignment of the resulting object by adding extra // padding at the start if required. size_t ExtraAlign = llvm::OffsetToAlignment(sizeof(Module *), alignof(Decl)); char *Buffer = reinterpret_cast( ::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx)); Buffer += ExtraAlign; - return new (Buffer) Module*(nullptr) + 1; + auto *ParentModule = + Parent ? cast(Parent)->getOwningModule() : nullptr; + return new (Buffer) Module*(ParentModule) + 1; } return ::operator new(Size + Extra, Ctx); } Module *Decl::getOwningModuleSlow() const { assert(isFromASTFile() && "Not from AST file?"); return getASTContext().getExternalSource()->getModule(getOwningModuleID()); } bool Decl::hasLocalOwningModuleStorage() const { - return getASTContext().getLangOpts().ModulesLocalVisibility; + return getASTContext().getLangOpts().trackLocalOwningModule(); } const char *Decl::getDeclKindName() const { switch (DeclKind) { default: llvm_unreachable("Declaration not in DeclNodes.inc!"); #define DECL(DERIVED, BASE) case DERIVED: return #DERIVED; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" } } void Decl::setInvalidDecl(bool Invalid) { InvalidDecl = Invalid; assert(!isa(this) || !cast(this)->isCompleteDefinition()); if (!Invalid) { return; } if (!isa(this)) { // Defensive maneuver for ill-formed code: we're likely not to make it to // a point where we set the access specifier, so default it to "public" // to avoid triggering asserts elsewhere in the front end. setAccess(AS_public); } // Marking a DecompositionDecl as invalid implies all the child BindingDecl's // are invalid too. if (DecompositionDecl *DD = dyn_cast(this)) { for (BindingDecl *Binding : DD->bindings()) { Binding->setInvalidDecl(); } } } const char *DeclContext::getDeclKindName() const { switch (DeclKind) { default: llvm_unreachable("Declaration context not in DeclNodes.inc!"); #define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" } } bool Decl::StatisticsEnabled = false; void Decl::EnableStatistics() { StatisticsEnabled = true; } void Decl::PrintStats() { llvm::errs() << "\n*** Decl Stats:\n"; int totalDecls = 0; #define DECL(DERIVED, BASE) totalDecls += n##DERIVED##s; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" llvm::errs() << " " << totalDecls << " decls total.\n"; int totalBytes = 0; #define DECL(DERIVED, BASE) \ if (n##DERIVED##s > 0) { \ totalBytes += (int)(n##DERIVED##s * sizeof(DERIVED##Decl)); \ llvm::errs() << " " << n##DERIVED##s << " " #DERIVED " decls, " \ << sizeof(DERIVED##Decl) << " each (" \ << n##DERIVED##s * sizeof(DERIVED##Decl) \ << " bytes)\n"; \ } #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" llvm::errs() << "Total bytes = " << totalBytes << "\n"; } void Decl::add(Kind k) { switch (k) { #define DECL(DERIVED, BASE) case DERIVED: ++n##DERIVED##s; break; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" } } bool Decl::isTemplateParameterPack() const { if (const TemplateTypeParmDecl *TTP = dyn_cast(this)) return TTP->isParameterPack(); if (const NonTypeTemplateParmDecl *NTTP = dyn_cast(this)) return NTTP->isParameterPack(); if (const TemplateTemplateParmDecl *TTP = dyn_cast(this)) return TTP->isParameterPack(); return false; } bool Decl::isParameterPack() const { if (const ParmVarDecl *Parm = dyn_cast(this)) return Parm->isParameterPack(); return isTemplateParameterPack(); } FunctionDecl *Decl::getAsFunction() { if (FunctionDecl *FD = dyn_cast(this)) return FD; if (const FunctionTemplateDecl *FTD = dyn_cast(this)) return FTD->getTemplatedDecl(); return nullptr; } bool Decl::isTemplateDecl() const { return isa(this); } TemplateDecl *Decl::getDescribedTemplate() const { if (auto *FD = dyn_cast(this)) return FD->getDescribedFunctionTemplate(); else if (auto *RD = dyn_cast(this)) return RD->getDescribedClassTemplate(); else if (auto *VD = dyn_cast(this)) return VD->getDescribedVarTemplate(); return nullptr; } const DeclContext *Decl::getParentFunctionOrMethod() const { for (const DeclContext *DC = getDeclContext(); DC && !DC->isTranslationUnit() && !DC->isNamespace(); DC = DC->getParent()) if (DC->isFunctionOrMethod()) return DC; return nullptr; } //===----------------------------------------------------------------------===// // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// void PrettyStackTraceDecl::print(raw_ostream &OS) const { SourceLocation TheLoc = Loc; if (TheLoc.isInvalid() && TheDecl) TheLoc = TheDecl->getLocation(); if (TheLoc.isValid()) { TheLoc.print(OS, SM); OS << ": "; } OS << Message; if (const NamedDecl *DN = dyn_cast_or_null(TheDecl)) { OS << " '"; DN->printQualifiedName(OS); OS << '\''; } OS << '\n'; } //===----------------------------------------------------------------------===// // Decl Implementation //===----------------------------------------------------------------------===// // Out-of-line virtual method providing a home for Decl. Decl::~Decl() { } void Decl::setDeclContext(DeclContext *DC) { DeclCtx = DC; } void Decl::setLexicalDeclContext(DeclContext *DC) { if (DC == getLexicalDeclContext()) return; if (isInSemaDC()) { setDeclContextsImpl(getDeclContext(), DC, getASTContext()); } else { getMultipleDC()->LexicalDC = DC; } Hidden = cast(DC)->Hidden; + if (Hidden && !isFromASTFile() && hasLocalOwningModuleStorage()) + setLocalOwningModule(cast(DC)->getOwningModule()); } void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, ASTContext &Ctx) { if (SemaDC == LexicalDC) { DeclCtx = SemaDC; } else { Decl::MultipleDC *MDC = new (Ctx) Decl::MultipleDC(); MDC->SemanticDC = SemaDC; MDC->LexicalDC = LexicalDC; DeclCtx = MDC; } } bool Decl::isLexicallyWithinFunctionOrMethod() const { const DeclContext *LDC = getLexicalDeclContext(); while (true) { if (LDC->isFunctionOrMethod()) return true; if (!isa(LDC)) return false; LDC = LDC->getLexicalParent(); } return false; } bool Decl::isInAnonymousNamespace() const { const DeclContext *DC = getDeclContext(); do { if (const NamespaceDecl *ND = dyn_cast(DC)) if (ND->isAnonymousNamespace()) return true; } while ((DC = DC->getParent())); return false; } bool Decl::isInStdNamespace() const { return getDeclContext()->isStdNamespace(); } TranslationUnitDecl *Decl::getTranslationUnitDecl() { if (TranslationUnitDecl *TUD = dyn_cast(this)) return TUD; DeclContext *DC = getDeclContext(); assert(DC && "This decl is not contained in a translation unit!"); while (!DC->isTranslationUnit()) { DC = DC->getParent(); assert(DC && "This decl is not contained in a translation unit!"); } return cast(DC); } ASTContext &Decl::getASTContext() const { return getTranslationUnitDecl()->getASTContext(); } ASTMutationListener *Decl::getASTMutationListener() const { return getASTContext().getASTMutationListener(); } unsigned Decl::getMaxAlignment() const { if (!hasAttrs()) return 0; unsigned Align = 0; const AttrVec &V = getAttrs(); ASTContext &Ctx = getASTContext(); specific_attr_iterator I(V.begin()), E(V.end()); for (; I != E; ++I) Align = std::max(Align, I->getAlignment(Ctx)); return Align; } bool Decl::isUsed(bool CheckUsedAttr) const { const Decl *CanonD = getCanonicalDecl(); if (CanonD->Used) return true; // Check for used attribute. // Ask the most recent decl, since attributes accumulate in the redecl chain. if (CheckUsedAttr && getMostRecentDecl()->hasAttr()) return true; // The information may have not been deserialized yet. Force deserialization // to complete the needed information. return getMostRecentDecl()->getCanonicalDecl()->Used; } void Decl::markUsed(ASTContext &C) { if (isUsed(false)) return; if (C.getASTMutationListener()) C.getASTMutationListener()->DeclarationMarkedUsed(this); setIsUsed(); } bool Decl::isReferenced() const { if (Referenced) return true; // Check redeclarations. for (auto I : redecls()) if (I->Referenced) return true; return false; } bool Decl::isExported() const { if (isModulePrivate()) return false; // Namespaces are always exported. if (isa(this) || isa(this)) return true; // Otherwise, this is a strictly lexical check. for (auto *DC = getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) { if (cast(DC)->isModulePrivate()) return false; if (isa(DC)) return true; } return false; } bool Decl::hasDefiningAttr() const { return hasAttr() || hasAttr(); } const Attr *Decl::getDefiningAttr() const { if (AliasAttr *AA = getAttr()) return AA; if (IFuncAttr *IFA = getAttr()) return IFA; return nullptr; } StringRef getRealizedPlatform(const AvailabilityAttr *A, const ASTContext &Context) { // Check if this is an App Extension "platform", and if so chop off // the suffix for matching with the actual platform. StringRef RealizedPlatform = A->getPlatform()->getName(); if (!Context.getLangOpts().AppExt) return RealizedPlatform; size_t suffix = RealizedPlatform.rfind("_app_extension"); if (suffix != StringRef::npos) return RealizedPlatform.slice(0, suffix); return RealizedPlatform; } /// \brief Determine the availability of the given declaration based on /// the target platform. /// /// When it returns an availability result other than \c AR_Available, /// if the \p Message parameter is non-NULL, it will be set to a /// string describing why the entity is unavailable. /// /// FIXME: Make these strings localizable, since they end up in /// diagnostics. static AvailabilityResult CheckAvailability(ASTContext &Context, const AvailabilityAttr *A, std::string *Message, VersionTuple EnclosingVersion) { if (EnclosingVersion.empty()) EnclosingVersion = Context.getTargetInfo().getPlatformMinVersion(); if (EnclosingVersion.empty()) return AR_Available; StringRef ActualPlatform = A->getPlatform()->getName(); StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); // Match the platform name. if (getRealizedPlatform(A, Context) != TargetPlatform) return AR_Available; StringRef PrettyPlatformName = AvailabilityAttr::getPrettyPlatformName(ActualPlatform); if (PrettyPlatformName.empty()) PrettyPlatformName = ActualPlatform; std::string HintMessage; if (!A->getMessage().empty()) { HintMessage = " - "; HintMessage += A->getMessage(); } // Make sure that this declaration has not been marked 'unavailable'. if (A->getUnavailable()) { if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); Out << "not available on " << PrettyPlatformName << HintMessage; } return AR_Unavailable; } // Make sure that this declaration has already been introduced. if (!A->getIntroduced().empty() && EnclosingVersion < A->getIntroduced()) { if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); VersionTuple VTI(A->getIntroduced()); VTI.UseDotAsSeparator(); Out << "introduced in " << PrettyPlatformName << ' ' << VTI << HintMessage; } return A->getStrict() ? AR_Unavailable : AR_NotYetIntroduced; } // Make sure that this declaration hasn't been obsoleted. if (!A->getObsoleted().empty() && EnclosingVersion >= A->getObsoleted()) { if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); VersionTuple VTO(A->getObsoleted()); VTO.UseDotAsSeparator(); Out << "obsoleted in " << PrettyPlatformName << ' ' << VTO << HintMessage; } return AR_Unavailable; } // Make sure that this declaration hasn't been deprecated. if (!A->getDeprecated().empty() && EnclosingVersion >= A->getDeprecated()) { if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); VersionTuple VTD(A->getDeprecated()); VTD.UseDotAsSeparator(); Out << "first deprecated in " << PrettyPlatformName << ' ' << VTD << HintMessage; } return AR_Deprecated; } return AR_Available; } AvailabilityResult Decl::getAvailability(std::string *Message, VersionTuple EnclosingVersion) const { if (auto *FTD = dyn_cast(this)) return FTD->getTemplatedDecl()->getAvailability(Message, EnclosingVersion); AvailabilityResult Result = AR_Available; std::string ResultMessage; for (const auto *A : attrs()) { if (const auto *Deprecated = dyn_cast(A)) { if (Result >= AR_Deprecated) continue; if (Message) ResultMessage = Deprecated->getMessage(); Result = AR_Deprecated; continue; } if (const auto *Unavailable = dyn_cast(A)) { if (Message) *Message = Unavailable->getMessage(); return AR_Unavailable; } if (const auto *Availability = dyn_cast(A)) { AvailabilityResult AR = CheckAvailability(getASTContext(), Availability, Message, EnclosingVersion); if (AR == AR_Unavailable) return AR_Unavailable; if (AR > Result) { Result = AR; if (Message) ResultMessage.swap(*Message); } continue; } } if (Message) Message->swap(ResultMessage); return Result; } VersionTuple Decl::getVersionIntroduced() const { const ASTContext &Context = getASTContext(); StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); for (const auto *A : attrs()) { if (const auto *Availability = dyn_cast(A)) { if (getRealizedPlatform(Availability, Context) != TargetPlatform) continue; if (!Availability->getIntroduced().empty()) return Availability->getIntroduced(); } } return VersionTuple(); } bool Decl::canBeWeakImported(bool &IsDefinition) const { IsDefinition = false; // Variables, if they aren't definitions. if (const VarDecl *Var = dyn_cast(this)) { if (Var->isThisDeclarationADefinition()) { IsDefinition = true; return false; } return true; // Functions, if they aren't definitions. } else if (const FunctionDecl *FD = dyn_cast(this)) { if (FD->hasBody()) { IsDefinition = true; return false; } return true; // Objective-C classes, if this is the non-fragile runtime. } else if (isa(this) && getASTContext().getLangOpts().ObjCRuntime.hasWeakClassImport()) { return true; // Nothing else. } else { return false; } } bool Decl::isWeakImported() const { bool IsDefinition; if (!canBeWeakImported(IsDefinition)) return false; for (const auto *A : attrs()) { if (isa(A)) return true; if (const auto *Availability = dyn_cast(A)) { if (CheckAvailability(getASTContext(), Availability, nullptr, VersionTuple()) == AR_NotYetIntroduced) return true; } } return false; } unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { switch (DeclKind) { case Function: case CXXDeductionGuide: case CXXMethod: case CXXConstructor: case ConstructorUsingShadow: case CXXDestructor: case CXXConversion: case EnumConstant: case Var: case Binding: case ImplicitParam: case ParmVar: case ObjCMethod: case ObjCProperty: case MSProperty: return IDNS_Ordinary; case Label: return IDNS_Label; case IndirectField: return IDNS_Ordinary | IDNS_Member; case NonTypeTemplateParm: // Non-type template parameters are not found by lookups that ignore // non-types, but they are found by redeclaration lookups for tag types, // so we include them in the tag namespace. return IDNS_Ordinary | IDNS_Tag; case ObjCCompatibleAlias: case ObjCInterface: return IDNS_Ordinary | IDNS_Type; case Typedef: case TypeAlias: case TypeAliasTemplate: case TemplateTypeParm: case ObjCTypeParam: return IDNS_Ordinary | IDNS_Type; case UnresolvedUsingTypename: return IDNS_Ordinary | IDNS_Type | IDNS_Using; case UsingShadow: return 0; // we'll actually overwrite this later case UnresolvedUsingValue: return IDNS_Ordinary | IDNS_Using; case Using: case UsingPack: return IDNS_Using; case ObjCProtocol: return IDNS_ObjCProtocol; case Field: case ObjCAtDefsField: case ObjCIvar: return IDNS_Member; case Record: case CXXRecord: case Enum: return IDNS_Tag | IDNS_Type; case Namespace: case NamespaceAlias: return IDNS_Namespace; case FunctionTemplate: case VarTemplate: return IDNS_Ordinary; case ClassTemplate: case TemplateTemplateParm: return IDNS_Ordinary | IDNS_Tag | IDNS_Type; case OMPDeclareReduction: return IDNS_OMPReduction; // Never have names. case Friend: case FriendTemplate: case AccessSpec: case LinkageSpec: case Export: case FileScopeAsm: case StaticAssert: case ObjCPropertyImpl: case PragmaComment: case PragmaDetectMismatch: case Block: case Captured: case TranslationUnit: case ExternCContext: case Decomposition: case UsingDirective: case BuiltinTemplate: case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: case ClassScopeFunctionSpecialization: case VarTemplateSpecialization: case VarTemplatePartialSpecialization: case ObjCImplementation: case ObjCCategory: case ObjCCategoryImpl: case Import: case OMPThreadPrivate: case OMPCapturedExpr: case Empty: // Never looked up by name. return 0; } llvm_unreachable("Invalid DeclKind!"); } void Decl::setAttrsImpl(const AttrVec &attrs, ASTContext &Ctx) { assert(!HasAttrs && "Decl already contains attrs."); AttrVec &AttrBlank = Ctx.getDeclAttrs(this); assert(AttrBlank.empty() && "HasAttrs was wrong?"); AttrBlank = attrs; HasAttrs = true; } void Decl::dropAttrs() { if (!HasAttrs) return; HasAttrs = false; getASTContext().eraseDeclAttrs(this); } const AttrVec &Decl::getAttrs() const { assert(HasAttrs && "No attrs to get!"); return getASTContext().getDeclAttrs(this); } Decl *Decl::castFromDeclContext (const DeclContext *D) { Decl::Kind DK = D->getDeclKind(); switch(DK) { #define DECL(NAME, BASE) #define DECL_CONTEXT(NAME) \ case Decl::NAME: \ return static_cast(const_cast(D)); #define DECL_CONTEXT_BASE(NAME) #include "clang/AST/DeclNodes.inc" default: #define DECL(NAME, BASE) #define DECL_CONTEXT_BASE(NAME) \ if (DK >= first##NAME && DK <= last##NAME) \ return static_cast(const_cast(D)); #include "clang/AST/DeclNodes.inc" llvm_unreachable("a decl that inherits DeclContext isn't handled"); } } DeclContext *Decl::castToDeclContext(const Decl *D) { Decl::Kind DK = D->getKind(); switch(DK) { #define DECL(NAME, BASE) #define DECL_CONTEXT(NAME) \ case Decl::NAME: \ return static_cast(const_cast(D)); #define DECL_CONTEXT_BASE(NAME) #include "clang/AST/DeclNodes.inc" default: #define DECL(NAME, BASE) #define DECL_CONTEXT_BASE(NAME) \ if (DK >= first##NAME && DK <= last##NAME) \ return static_cast(const_cast(D)); #include "clang/AST/DeclNodes.inc" llvm_unreachable("a decl that inherits DeclContext isn't handled"); } } SourceLocation Decl::getBodyRBrace() const { // Special handling of FunctionDecl to avoid de-serializing the body from PCH. // FunctionDecl stores EndRangeLoc for this purpose. if (const FunctionDecl *FD = dyn_cast(this)) { const FunctionDecl *Definition; if (FD->hasBody(Definition)) return Definition->getSourceRange().getEnd(); return SourceLocation(); } if (Stmt *Body = getBody()) return Body->getSourceRange().getEnd(); return SourceLocation(); } bool Decl::AccessDeclContextSanity() const { #ifndef NDEBUG // Suppress this check if any of the following hold: // 1. this is the translation unit (and thus has no parent) // 2. this is a template parameter (and thus doesn't belong to its context) // 3. this is a non-type template parameter // 4. the context is not a record // 5. it's invalid // 6. it's a C++0x static_assert. if (isa(this) || isa(this) || isa(this) || !isa(getDeclContext()) || isInvalidDecl() || isa(this) || // FIXME: a ParmVarDecl can have ClassTemplateSpecialization // as DeclContext (?). isa(this) || // FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have // AS_none as access specifier. isa(this) || isa(this)) return true; assert(Access != AS_none && "Access specifier is AS_none inside a record decl"); #endif return true; } static Decl::Kind getKind(const Decl *D) { return D->getKind(); } static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); } const FunctionType *Decl::getFunctionType(bool BlocksToo) const { QualType Ty; if (const ValueDecl *D = dyn_cast(this)) Ty = D->getType(); else if (const TypedefNameDecl *D = dyn_cast(this)) Ty = D->getUnderlyingType(); else return nullptr; if (Ty->isFunctionPointerType()) Ty = Ty->getAs()->getPointeeType(); else if (BlocksToo && Ty->isBlockPointerType()) Ty = Ty->getAs()->getPointeeType(); return Ty->getAs(); } /// Starting at a given context (a Decl or DeclContext), look for a /// code context that is not a closure (a lambda, block, etc.). template static Decl *getNonClosureContext(T *D) { if (getKind(D) == Decl::CXXMethod) { CXXMethodDecl *MD = cast(D); if (MD->getOverloadedOperator() == OO_Call && MD->getParent()->isLambda()) return getNonClosureContext(MD->getParent()->getParent()); return MD; } else if (FunctionDecl *FD = dyn_cast(D)) { return FD; } else if (ObjCMethodDecl *MD = dyn_cast(D)) { return MD; } else if (BlockDecl *BD = dyn_cast(D)) { return getNonClosureContext(BD->getParent()); } else if (CapturedDecl *CD = dyn_cast(D)) { return getNonClosureContext(CD->getParent()); } else { return nullptr; } } Decl *Decl::getNonClosureContext() { return ::getNonClosureContext(this); } Decl *DeclContext::getNonClosureAncestor() { return ::getNonClosureContext(this); } //===----------------------------------------------------------------------===// // DeclContext Implementation //===----------------------------------------------------------------------===// bool DeclContext::classof(const Decl *D) { switch (D->getKind()) { #define DECL(NAME, BASE) #define DECL_CONTEXT(NAME) case Decl::NAME: #define DECL_CONTEXT_BASE(NAME) #include "clang/AST/DeclNodes.inc" return true; default: #define DECL(NAME, BASE) #define DECL_CONTEXT_BASE(NAME) \ if (D->getKind() >= Decl::first##NAME && \ D->getKind() <= Decl::last##NAME) \ return true; #include "clang/AST/DeclNodes.inc" return false; } } DeclContext::~DeclContext() { } /// \brief Find the parent context of this context that will be /// used for unqualified name lookup. /// /// Generally, the parent lookup context is the semantic context. However, for /// a friend function the parent lookup context is the lexical context, which /// is the class in which the friend is declared. DeclContext *DeclContext::getLookupParent() { // FIXME: Find a better way to identify friends if (isa(this)) if (getParent()->getRedeclContext()->isFileContext() && getLexicalParent()->getRedeclContext()->isRecord()) return getLexicalParent(); return getParent(); } bool DeclContext::isInlineNamespace() const { return isNamespace() && cast(this)->isInline(); } bool DeclContext::isStdNamespace() const { if (!isNamespace()) return false; const NamespaceDecl *ND = cast(this); if (ND->isInline()) { return ND->getParent()->isStdNamespace(); } if (!getParent()->getRedeclContext()->isTranslationUnit()) return false; const IdentifierInfo *II = ND->getIdentifier(); return II && II->isStr("std"); } bool DeclContext::isDependentContext() const { if (isFileContext()) return false; if (isa(this)) return true; if (const CXXRecordDecl *Record = dyn_cast(this)) { if (Record->getDescribedClassTemplate()) return true; if (Record->isDependentLambda()) return true; } if (const FunctionDecl *Function = dyn_cast(this)) { if (Function->getDescribedFunctionTemplate()) return true; // Friend function declarations are dependent if their *lexical* // context is dependent. if (cast(this)->getFriendObjectKind()) return getLexicalParent()->isDependentContext(); } // FIXME: A variable template is a dependent context, but is not a // DeclContext. A context within it (such as a lambda-expression) // should be considered dependent. return getParent() && getParent()->isDependentContext(); } bool DeclContext::isTransparentContext() const { if (DeclKind == Decl::Enum) return !cast(this)->isScoped(); else if (DeclKind == Decl::LinkageSpec || DeclKind == Decl::Export) return true; return false; } static bool isLinkageSpecContext(const DeclContext *DC, LinkageSpecDecl::LanguageIDs ID) { while (DC->getDeclKind() != Decl::TranslationUnit) { if (DC->getDeclKind() == Decl::LinkageSpec) return cast(DC)->getLanguage() == ID; DC = DC->getLexicalParent(); } return false; } bool DeclContext::isExternCContext() const { return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c); } const LinkageSpecDecl *DeclContext::getExternCContext() const { const DeclContext *DC = this; while (DC->getDeclKind() != Decl::TranslationUnit) { if (DC->getDeclKind() == Decl::LinkageSpec && cast(DC)->getLanguage() == clang::LinkageSpecDecl::lang_c) return cast(DC); DC = DC->getLexicalParent(); } return nullptr; } bool DeclContext::isExternCXXContext() const { return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx); } bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); for (; DC; DC = DC->getParent()) if (DC->getPrimaryContext() == this) return true; return false; } DeclContext *DeclContext::getPrimaryContext() { switch (DeclKind) { case Decl::TranslationUnit: case Decl::ExternCContext: case Decl::LinkageSpec: case Decl::Export: case Decl::Block: case Decl::Captured: case Decl::OMPDeclareReduction: // There is only one DeclContext for these entities. return this; case Decl::Namespace: // The original namespace is our primary context. return static_cast(this)->getOriginalNamespace(); case Decl::ObjCMethod: return this; case Decl::ObjCInterface: if (ObjCInterfaceDecl *Def = cast(this)->getDefinition()) return Def; return this; case Decl::ObjCProtocol: if (ObjCProtocolDecl *Def = cast(this)->getDefinition()) return Def; return this; case Decl::ObjCCategory: return this; case Decl::ObjCImplementation: case Decl::ObjCCategoryImpl: return this; default: if (DeclKind >= Decl::firstTag && DeclKind <= Decl::lastTag) { // If this is a tag type that has a definition or is currently // being defined, that definition is our primary context. TagDecl *Tag = cast(this); if (TagDecl *Def = Tag->getDefinition()) return Def; if (const TagType *TagTy = dyn_cast(Tag->getTypeForDecl())) { // Note, TagType::getDecl returns the (partial) definition one exists. TagDecl *PossiblePartialDef = TagTy->getDecl(); if (PossiblePartialDef->isBeingDefined()) return PossiblePartialDef; } else { assert(isa(Tag->getTypeForDecl())); } return Tag; } assert(DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction && "Unknown DeclContext kind"); return this; } } void DeclContext::collectAllContexts(SmallVectorImpl &Contexts){ Contexts.clear(); if (DeclKind != Decl::Namespace) { Contexts.push_back(this); return; } NamespaceDecl *Self = static_cast(this); for (NamespaceDecl *N = Self->getMostRecentDecl(); N; N = N->getPreviousDecl()) Contexts.push_back(N); std::reverse(Contexts.begin(), Contexts.end()); } std::pair DeclContext::BuildDeclChain(ArrayRef Decls, bool FieldsAlreadyLoaded) { // Build up a chain of declarations via the Decl::NextInContextAndBits field. Decl *FirstNewDecl = nullptr; Decl *PrevDecl = nullptr; for (unsigned I = 0, N = Decls.size(); I != N; ++I) { if (FieldsAlreadyLoaded && isa(Decls[I])) continue; Decl *D = Decls[I]; if (PrevDecl) PrevDecl->NextInContextAndBits.setPointer(D); else FirstNewDecl = D; PrevDecl = D; } return std::make_pair(FirstNewDecl, PrevDecl); } /// \brief We have just acquired external visible storage, and we already have /// built a lookup map. For every name in the map, pull in the new names from /// the external storage. void DeclContext::reconcileExternalVisibleStorage() const { assert(NeedToReconcileExternalVisibleStorage && LookupPtr); NeedToReconcileExternalVisibleStorage = false; for (auto &Lookup : *LookupPtr) Lookup.second.setHasExternalDecls(); } /// \brief Load the declarations within this lexical storage from an /// external source. /// \return \c true if any declarations were added. bool DeclContext::LoadLexicalDeclsFromExternalStorage() const { ExternalASTSource *Source = getParentASTContext().getExternalSource(); assert(hasExternalLexicalStorage() && Source && "No external storage?"); // Notify that we have a DeclContext that is initializing. ExternalASTSource::Deserializing ADeclContext(Source); // Load the external declarations, if any. SmallVector Decls; ExternalLexicalStorage = false; Source->FindExternalLexicalDecls(this, Decls); if (Decls.empty()) return false; // We may have already loaded just the fields of this record, in which case // we need to ignore them. bool FieldsAlreadyLoaded = false; if (const RecordDecl *RD = dyn_cast(this)) FieldsAlreadyLoaded = RD->LoadedFieldsFromExternalStorage; // Splice the newly-read declarations into the beginning of the list // of declarations. Decl *ExternalFirst, *ExternalLast; std::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls, FieldsAlreadyLoaded); ExternalLast->NextInContextAndBits.setPointer(FirstDecl); FirstDecl = ExternalFirst; if (!LastDecl) LastDecl = ExternalLast; return true; } DeclContext::lookup_result ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name) { ASTContext &Context = DC->getParentASTContext(); StoredDeclsMap *Map; if (!(Map = DC->LookupPtr)) Map = DC->CreateStoredDeclsMap(Context); if (DC->NeedToReconcileExternalVisibleStorage) DC->reconcileExternalVisibleStorage(); (*Map)[Name].removeExternalDecls(); return DeclContext::lookup_result(); } DeclContext::lookup_result ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name, ArrayRef Decls) { ASTContext &Context = DC->getParentASTContext(); StoredDeclsMap *Map; if (!(Map = DC->LookupPtr)) Map = DC->CreateStoredDeclsMap(Context); if (DC->NeedToReconcileExternalVisibleStorage) DC->reconcileExternalVisibleStorage(); StoredDeclsList &List = (*Map)[Name]; // Clear out any old external visible declarations, to avoid quadratic // performance in the redeclaration checks below. List.removeExternalDecls(); if (!List.isNull()) { // We have both existing declarations and new declarations for this name. // Some of the declarations may simply replace existing ones. Handle those // first. llvm::SmallVector Skip; for (unsigned I = 0, N = Decls.size(); I != N; ++I) if (List.HandleRedeclaration(Decls[I], /*IsKnownNewer*/false)) Skip.push_back(I); Skip.push_back(Decls.size()); // Add in any new declarations. unsigned SkipPos = 0; for (unsigned I = 0, N = Decls.size(); I != N; ++I) { if (I == Skip[SkipPos]) ++SkipPos; else List.AddSubsequentDecl(Decls[I]); } } else { // Convert the array to a StoredDeclsList. for (ArrayRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { if (List.isNull()) List.setOnlyValue(*I); else List.AddSubsequentDecl(*I); } } return List.getLookupResult(); } DeclContext::decl_iterator DeclContext::decls_begin() const { if (hasExternalLexicalStorage()) LoadLexicalDeclsFromExternalStorage(); return decl_iterator(FirstDecl); } bool DeclContext::decls_empty() const { if (hasExternalLexicalStorage()) LoadLexicalDeclsFromExternalStorage(); return !FirstDecl; } bool DeclContext::containsDecl(Decl *D) const { return (D->getLexicalDeclContext() == this && (D->NextInContextAndBits.getPointer() || D == LastDecl)); } void DeclContext::removeDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "decl being removed from non-lexical context"); assert((D->NextInContextAndBits.getPointer() || D == LastDecl) && "decl is not in decls list"); // Remove D from the decl chain. This is O(n) but hopefully rare. if (D == FirstDecl) { if (D == LastDecl) FirstDecl = LastDecl = nullptr; else FirstDecl = D->NextInContextAndBits.getPointer(); } else { for (Decl *I = FirstDecl; true; I = I->NextInContextAndBits.getPointer()) { assert(I && "decl not found in linked list"); if (I->NextInContextAndBits.getPointer() == D) { I->NextInContextAndBits.setPointer(D->NextInContextAndBits.getPointer()); if (D == LastDecl) LastDecl = I; break; } } } // Mark that D is no longer in the decl chain. D->NextInContextAndBits.setPointer(nullptr); // Remove D from the lookup table if necessary. if (isa(D)) { NamedDecl *ND = cast(D); // Remove only decls that have a name if (!ND->getDeclName()) return; auto *DC = this; do { StoredDeclsMap *Map = DC->getPrimaryContext()->LookupPtr; if (Map) { StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); assert(Pos != Map->end() && "no lookup entry for decl"); if (Pos->second.getAsVector() || Pos->second.getAsDecl() == ND) Pos->second.remove(ND); } } while (DC->isTransparentContext() && (DC = DC->getParent())); } } void DeclContext::addHiddenDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "Decl inserted into wrong lexical context"); assert(!D->getNextDeclInContext() && D != LastDecl && "Decl already inserted into a DeclContext"); if (FirstDecl) { LastDecl->NextInContextAndBits.setPointer(D); LastDecl = D; } else { FirstDecl = LastDecl = D; } // Notify a C++ record declaration that we've added a member, so it can // update its class-specific state. if (CXXRecordDecl *Record = dyn_cast(this)) Record->addedMember(D); // If this is a newly-created (not de-serialized) import declaration, wire // it in to the list of local import declarations. if (!D->isFromASTFile()) { if (ImportDecl *Import = dyn_cast(D)) D->getASTContext().addedLocalImportDecl(Import); } } void DeclContext::addDecl(Decl *D) { addHiddenDecl(D); if (NamedDecl *ND = dyn_cast(D)) ND->getDeclContext()->getPrimaryContext()-> makeDeclVisibleInContextWithFlags(ND, false, true); } void DeclContext::addDeclInternal(Decl *D) { addHiddenDecl(D); if (NamedDecl *ND = dyn_cast(D)) ND->getDeclContext()->getPrimaryContext()-> makeDeclVisibleInContextWithFlags(ND, true, true); } /// shouldBeHidden - Determine whether a declaration which was declared /// within its semantic context should be invisible to qualified name lookup. static bool shouldBeHidden(NamedDecl *D) { // Skip unnamed declarations. if (!D->getDeclName()) return true; // Skip entities that can't be found by name lookup into a particular // context. if ((D->getIdentifierNamespace() == 0 && !isa(D)) || D->isTemplateParameter()) return true; // Skip template specializations. // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? if (isa(D)) return true; if (FunctionDecl *FD = dyn_cast(D)) if (FD->isFunctionTemplateSpecialization()) return true; return false; } /// buildLookup - Build the lookup data structure with all of the /// declarations in this DeclContext (and any other contexts linked /// to it or transparent contexts nested within it) and return it. /// /// Note that the produced map may miss out declarations from an /// external source. If it does, those entries will be marked with /// the 'hasExternalDecls' flag. StoredDeclsMap *DeclContext::buildLookup() { assert(this == getPrimaryContext() && "buildLookup called on non-primary DC"); if (!HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) return LookupPtr; SmallVector Contexts; collectAllContexts(Contexts); if (HasLazyExternalLexicalLookups) { HasLazyExternalLexicalLookups = false; for (auto *DC : Contexts) { if (DC->hasExternalLexicalStorage()) HasLazyLocalLexicalLookups |= DC->LoadLexicalDeclsFromExternalStorage(); } if (!HasLazyLocalLexicalLookups) return LookupPtr; } for (auto *DC : Contexts) buildLookupImpl(DC, hasExternalVisibleStorage()); // We no longer have any lazy decls. HasLazyLocalLexicalLookups = false; return LookupPtr; } /// buildLookupImpl - Build part of the lookup data structure for the /// declarations contained within DCtx, which will either be this /// DeclContext, a DeclContext linked to it, or a transparent context /// nested within it. void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) { for (Decl *D : DCtx->noload_decls()) { // Insert this declaration into the lookup structure, but only if // it's semantically within its decl context. Any other decls which // should be found in this context are added eagerly. // // If it's from an AST file, don't add it now. It'll get handled by // FindExternalVisibleDeclsByName if needed. Exception: if we're not // in C++, we do not track external visible decls for the TU, so in // that case we need to collect them all here. if (NamedDecl *ND = dyn_cast(D)) if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND) && (!ND->isFromASTFile() || (isTranslationUnit() && !getParentASTContext().getLangOpts().CPlusPlus))) makeDeclVisibleInContextImpl(ND, Internal); // If this declaration is itself a transparent declaration context // or inline namespace, add the members of this declaration of that // context (recursively). if (DeclContext *InnerCtx = dyn_cast(D)) if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) buildLookupImpl(InnerCtx, Internal); } } NamedDecl *const DeclContextLookupResult::SingleElementDummyList = nullptr; DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) const { assert(DeclKind != Decl::LinkageSpec && DeclKind != Decl::Export && "should not perform lookups into transparent contexts"); const DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) return PrimaryContext->lookup(Name); // If we have an external source, ensure that any later redeclarations of this // context have been loaded, since they may add names to the result of this // lookup (or add external visible storage). ExternalASTSource *Source = getParentASTContext().getExternalSource(); if (Source) (void)cast(this)->getMostRecentDecl(); if (hasExternalVisibleStorage()) { assert(Source && "external visible storage but no external source?"); if (NeedToReconcileExternalVisibleStorage) reconcileExternalVisibleStorage(); StoredDeclsMap *Map = LookupPtr; if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups) // FIXME: Make buildLookup const? Map = const_cast(this)->buildLookup(); if (!Map) Map = CreateStoredDeclsMap(getParentASTContext()); // If we have a lookup result with no external decls, we are done. std::pair R = Map->insert(std::make_pair(Name, StoredDeclsList())); if (!R.second && !R.first->second.hasExternalDecls()) return R.first->second.getLookupResult(); if (Source->FindExternalVisibleDeclsByName(this, Name) || !R.second) { if (StoredDeclsMap *Map = LookupPtr) { StoredDeclsMap::iterator I = Map->find(Name); if (I != Map->end()) return I->second.getLookupResult(); } } return lookup_result(); } StoredDeclsMap *Map = LookupPtr; if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups) Map = const_cast(this)->buildLookup(); if (!Map) return lookup_result(); StoredDeclsMap::iterator I = Map->find(Name); if (I == Map->end()) return lookup_result(); return I->second.getLookupResult(); } DeclContext::lookup_result DeclContext::noload_lookup(DeclarationName Name) { assert(DeclKind != Decl::LinkageSpec && DeclKind != Decl::Export && "should not perform lookups into transparent contexts"); DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) return PrimaryContext->noload_lookup(Name); // If we have any lazy lexical declarations not in our lookup map, add them // now. Don't import any external declarations, not even if we know we have // some missing from the external visible lookups. if (HasLazyLocalLexicalLookups) { SmallVector Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) buildLookupImpl(Contexts[I], hasExternalVisibleStorage()); HasLazyLocalLexicalLookups = false; } StoredDeclsMap *Map = LookupPtr; if (!Map) return lookup_result(); StoredDeclsMap::iterator I = Map->find(Name); return I != Map->end() ? I->second.getLookupResult() : lookup_result(); } void DeclContext::localUncachedLookup(DeclarationName Name, SmallVectorImpl &Results) { Results.clear(); // If there's no external storage, just perform a normal lookup and copy // the results. if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) { lookup_result LookupResults = lookup(Name); Results.insert(Results.end(), LookupResults.begin(), LookupResults.end()); return; } // If we have a lookup table, check there first. Maybe we'll get lucky. // FIXME: Should we be checking these flags on the primary context? if (Name && !HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) { if (StoredDeclsMap *Map = LookupPtr) { StoredDeclsMap::iterator Pos = Map->find(Name); if (Pos != Map->end()) { Results.insert(Results.end(), Pos->second.getLookupResult().begin(), Pos->second.getLookupResult().end()); return; } } } // Slow case: grovel through the declarations in our chain looking for // matches. // FIXME: If we have lazy external declarations, this will not find them! // FIXME: Should we CollectAllContexts and walk them all here? for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { if (NamedDecl *ND = dyn_cast(D)) if (ND->getDeclName() == Name) Results.push_back(ND); } } DeclContext *DeclContext::getRedeclContext() { DeclContext *Ctx = this; // Skip through transparent contexts. while (Ctx->isTransparentContext()) Ctx = Ctx->getParent(); return Ctx; } DeclContext *DeclContext::getEnclosingNamespaceContext() { DeclContext *Ctx = this; // Skip through non-namespace, non-translation-unit contexts. while (!Ctx->isFileContext()) Ctx = Ctx->getParent(); return Ctx->getPrimaryContext(); } RecordDecl *DeclContext::getOuterLexicalRecordContext() { // Loop until we find a non-record context. RecordDecl *OutermostRD = nullptr; DeclContext *DC = this; while (DC->isRecord()) { OutermostRD = cast(DC); DC = DC->getLexicalParent(); } return OutermostRD; } bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const { // For non-file contexts, this is equivalent to Equals. if (!isFileContext()) return O->Equals(this); do { if (O->Equals(this)) return true; const NamespaceDecl *NS = dyn_cast(O); if (!NS || !NS->isInline()) break; O = NS->getParent(); } while (O); return false; } void DeclContext::makeDeclVisibleInContext(NamedDecl *D) { DeclContext *PrimaryDC = this->getPrimaryContext(); DeclContext *DeclDC = D->getDeclContext()->getPrimaryContext(); // If the decl is being added outside of its semantic decl context, we // need to ensure that we eagerly build the lookup information for it. PrimaryDC->makeDeclVisibleInContextWithFlags(D, false, PrimaryDC == DeclDC); } void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, bool Recoverable) { assert(this == getPrimaryContext() && "expected a primary DC"); if (!isLookupContext()) { if (isTransparentContext()) getParent()->getPrimaryContext() ->makeDeclVisibleInContextWithFlags(D, Internal, Recoverable); return; } // Skip declarations which should be invisible to name lookup. if (shouldBeHidden(D)) return; // If we already have a lookup data structure, perform the insertion into // it. If we might have externally-stored decls with this name, look them // up and perform the insertion. If this decl was declared outside its // semantic context, buildLookup won't add it, so add it now. // // FIXME: As a performance hack, don't add such decls into the translation // unit unless we're in C++, since qualified lookup into the TU is never // performed. if (LookupPtr || hasExternalVisibleStorage() || ((!Recoverable || D->getDeclContext() != D->getLexicalDeclContext()) && (getParentASTContext().getLangOpts().CPlusPlus || !isTranslationUnit()))) { // If we have lazily omitted any decls, they might have the same name as // the decl which we are adding, so build a full lookup table before adding // this decl. buildLookup(); makeDeclVisibleInContextImpl(D, Internal); } else { HasLazyLocalLexicalLookups = true; } // If we are a transparent context or inline namespace, insert into our // parent context, too. This operation is recursive. if (isTransparentContext() || isInlineNamespace()) getParent()->getPrimaryContext()-> makeDeclVisibleInContextWithFlags(D, Internal, Recoverable); Decl *DCAsDecl = cast(this); // Notify that a decl was made visible unless we are a Tag being defined. if (!(isa(DCAsDecl) && cast(DCAsDecl)->isBeingDefined())) if (ASTMutationListener *L = DCAsDecl->getASTMutationListener()) L->AddedVisibleDecl(this, D); } void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { // Find or create the stored declaration map. StoredDeclsMap *Map = LookupPtr; if (!Map) { ASTContext *C = &getParentASTContext(); Map = CreateStoredDeclsMap(*C); } // If there is an external AST source, load any declarations it knows about // with this declaration's name. // If the lookup table contains an entry about this name it means that we // have already checked the external source. if (!Internal) if (ExternalASTSource *Source = getParentASTContext().getExternalSource()) if (hasExternalVisibleStorage() && Map->find(D->getDeclName()) == Map->end()) Source->FindExternalVisibleDeclsByName(this, D->getDeclName()); // Insert this declaration into the map. StoredDeclsList &DeclNameEntries = (*Map)[D->getDeclName()]; if (Internal) { // If this is being added as part of loading an external declaration, // this may not be the only external declaration with this name. // In this case, we never try to replace an existing declaration; we'll // handle that when we finalize the list of declarations for this name. DeclNameEntries.setHasExternalDecls(); DeclNameEntries.AddSubsequentDecl(D); return; } if (DeclNameEntries.isNull()) { DeclNameEntries.setOnlyValue(D); return; } if (DeclNameEntries.HandleRedeclaration(D, /*IsKnownNewer*/!Internal)) { // This declaration has replaced an existing one for which // declarationReplaces returns true. return; } // Put this declaration into the appropriate slot. DeclNameEntries.AddSubsequentDecl(D); } UsingDirectiveDecl *DeclContext::udir_iterator::operator*() const { return cast(*I); } /// Returns iterator range [First, Last) of UsingDirectiveDecls stored within /// this context. DeclContext::udir_range DeclContext::using_directives() const { // FIXME: Use something more efficient than normal lookup for using // directives. In C++, using directives are looked up more than anything else. lookup_result Result = lookup(UsingDirectiveDecl::getName()); return udir_range(Result.begin(), Result.end()); } //===----------------------------------------------------------------------===// // Creation and Destruction of StoredDeclsMaps. // //===----------------------------------------------------------------------===// StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const { assert(!LookupPtr && "context already has a decls map"); assert(getPrimaryContext() == this && "creating decls map on non-primary context"); StoredDeclsMap *M; bool Dependent = isDependentContext(); if (Dependent) M = new DependentStoredDeclsMap(); else M = new StoredDeclsMap(); M->Previous = C.LastSDM; C.LastSDM = llvm::PointerIntPair(M, Dependent); LookupPtr = M; return M; } void ASTContext::ReleaseDeclContextMaps() { // It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap // pointer because the subclass doesn't add anything that needs to // be deleted. StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt()); } void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) { while (Map) { // Advance the iteration before we invalidate memory. llvm::PointerIntPair Next = Map->Previous; if (Dependent) delete static_cast(Map); else delete Map; Map = Next.getPointer(); Dependent = Next.getInt(); } } DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C, DeclContext *Parent, const PartialDiagnostic &PDiag) { assert(Parent->isDependentContext() && "cannot iterate dependent diagnostics of non-dependent context"); Parent = Parent->getPrimaryContext(); if (!Parent->LookupPtr) Parent->CreateStoredDeclsMap(C); DependentStoredDeclsMap *Map = static_cast(Parent->LookupPtr); // Allocate the copy of the PartialDiagnostic via the ASTContext's // BumpPtrAllocator, rather than the ASTContext itself. PartialDiagnostic::Storage *DiagStorage = nullptr; if (PDiag.hasStorage()) DiagStorage = new (C) PartialDiagnostic::Storage; DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage); // TODO: Maybe we shouldn't reverse the order during insertion. DD->NextDiagnostic = Map->FirstDiagnostic; Map->FirstDiagnostic = DD; return DD; } Index: vendor/clang/dist/lib/AST/ODRHash.cpp =================================================================== --- vendor/clang/dist/lib/AST/ODRHash.cpp (revision 318415) +++ vendor/clang/dist/lib/AST/ODRHash.cpp (revision 318416) @@ -1,443 +1,521 @@ //===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// This file implements the ODRHash class, which calculates a hash based /// on AST nodes, which is stable across different runs. /// //===----------------------------------------------------------------------===// #include "clang/AST/ODRHash.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeVisitor.h" using namespace clang; void ODRHash::AddStmt(const Stmt *S) { assert(S && "Expecting non-null pointer."); S->ProcessODRHash(ID, *this); } void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) { assert(II && "Expecting non-null pointer."); ID.AddString(II->getName()); } void ODRHash::AddDeclarationName(DeclarationName Name) { AddBoolean(Name.isEmpty()); if (Name.isEmpty()) return; auto Kind = Name.getNameKind(); ID.AddInteger(Kind); switch (Kind) { case DeclarationName::Identifier: AddIdentifierInfo(Name.getAsIdentifierInfo()); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: { Selector S = Name.getObjCSelector(); AddBoolean(S.isNull()); AddBoolean(S.isKeywordSelector()); AddBoolean(S.isUnarySelector()); unsigned NumArgs = S.getNumArgs(); for (unsigned i = 0; i < NumArgs; ++i) { AddIdentifierInfo(S.getIdentifierInfoForSlot(i)); } break; } case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: AddQualType(Name.getCXXNameType()); break; case DeclarationName::CXXOperatorName: ID.AddInteger(Name.getCXXOverloadedOperator()); break; case DeclarationName::CXXLiteralOperatorName: AddIdentifierInfo(Name.getCXXLiteralIdentifier()); break; case DeclarationName::CXXConversionFunctionName: AddQualType(Name.getCXXNameType()); break; case DeclarationName::CXXUsingDirective: break; case DeclarationName::CXXDeductionGuideName: { auto *Template = Name.getCXXDeductionGuideTemplate(); AddBoolean(Template); if (Template) { AddDecl(Template); } } } } -void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {} +void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { + assert(NNS && "Expecting non-null pointer."); + const auto *Prefix = NNS->getPrefix(); + AddBoolean(Prefix); + if (Prefix) { + AddNestedNameSpecifier(Prefix); + } + auto Kind = NNS->getKind(); + ID.AddInteger(Kind); + switch (Kind) { + case NestedNameSpecifier::Identifier: + AddIdentifierInfo(NNS->getAsIdentifier()); + break; + case NestedNameSpecifier::Namespace: + AddDecl(NNS->getAsNamespace()); + break; + case NestedNameSpecifier::NamespaceAlias: + AddDecl(NNS->getAsNamespaceAlias()); + break; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + AddType(NNS->getAsType()); + break; + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: + break; + } +} + void ODRHash::AddTemplateName(TemplateName Name) {} void ODRHash::AddTemplateArgument(TemplateArgument TA) {} void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {} void ODRHash::clear() { DeclMap.clear(); TypeMap.clear(); Bools.clear(); ID.clear(); } unsigned ODRHash::CalculateHash() { // Append the bools to the end of the data segment backwards. This allows // for the bools data to be compressed 32 times smaller compared to using // ID.AddBoolean const unsigned unsigned_bits = sizeof(unsigned) * CHAR_BIT; const unsigned size = Bools.size(); const unsigned remainder = size % unsigned_bits; const unsigned loops = size / unsigned_bits; auto I = Bools.rbegin(); unsigned value = 0; for (unsigned i = 0; i < remainder; ++i) { value <<= 1; value |= *I; ++I; } ID.AddInteger(value); for (unsigned i = 0; i < loops; ++i) { value = 0; for (unsigned j = 0; j < unsigned_bits; ++j) { value <<= 1; value |= *I; ++I; } ID.AddInteger(value); } assert(I == Bools.rend()); Bools.clear(); return ID.ComputeHash(); } // Process a Decl pointer. Add* methods call back into ODRHash while Visit* // methods process the relevant parts of the Decl. class ODRDeclVisitor : public ConstDeclVisitor { typedef ConstDeclVisitor Inherited; llvm::FoldingSetNodeID &ID; ODRHash &Hash; public: ODRDeclVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash) : ID(ID), Hash(Hash) {} void AddStmt(const Stmt *S) { Hash.AddBoolean(S); if (S) { Hash.AddStmt(S); } } void AddIdentifierInfo(const IdentifierInfo *II) { Hash.AddBoolean(II); if (II) { Hash.AddIdentifierInfo(II); } } void AddQualType(QualType T) { Hash.AddQualType(T); } void Visit(const Decl *D) { ID.AddInteger(D->getKind()); Inherited::Visit(D); } void VisitNamedDecl(const NamedDecl *D) { Hash.AddDeclarationName(D->getDeclName()); Inherited::VisitNamedDecl(D); } void VisitValueDecl(const ValueDecl *D) { AddQualType(D->getType()); Inherited::VisitValueDecl(D); } void VisitParmVarDecl(const ParmVarDecl *D) { // TODO: Handle default arguments. Inherited::VisitParmVarDecl(D); } void VisitAccessSpecDecl(const AccessSpecDecl *D) { ID.AddInteger(D->getAccess()); Inherited::VisitAccessSpecDecl(D); } void VisitStaticAssertDecl(const StaticAssertDecl *D) { AddStmt(D->getAssertExpr()); AddStmt(D->getMessage()); Inherited::VisitStaticAssertDecl(D); } void VisitFieldDecl(const FieldDecl *D) { const bool IsBitfield = D->isBitField(); Hash.AddBoolean(IsBitfield); if (IsBitfield) { AddStmt(D->getBitWidth()); } Hash.AddBoolean(D->isMutable()); AddStmt(D->getInClassInitializer()); Inherited::VisitFieldDecl(D); } void VisitFunctionDecl(const FunctionDecl *D) { ID.AddInteger(D->getStorageClass()); Hash.AddBoolean(D->isInlineSpecified()); Hash.AddBoolean(D->isVirtualAsWritten()); Hash.AddBoolean(D->isPure()); Hash.AddBoolean(D->isDeletedAsWritten()); ID.AddInteger(D->param_size()); for (auto *Param : D->parameters()) { Hash.AddSubDecl(Param); } Inherited::VisitFunctionDecl(D); } void VisitCXXMethodDecl(const CXXMethodDecl *D) { Hash.AddBoolean(D->isConst()); Hash.AddBoolean(D->isVolatile()); Inherited::VisitCXXMethodDecl(D); } void VisitTypedefNameDecl(const TypedefNameDecl *D) { AddQualType(D->getUnderlyingType()); Inherited::VisitTypedefNameDecl(D); } void VisitTypedefDecl(const TypedefDecl *D) { Inherited::VisitTypedefDecl(D); } void VisitTypeAliasDecl(const TypeAliasDecl *D) { Inherited::VisitTypeAliasDecl(D); } }; // Only allow a small portion of Decl's to be processed. Remove this once // all Decl's can be handled. bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) { if (D->isImplicit()) return false; if (D->getDeclContext() != Parent) return false; switch (D->getKind()) { default: return false; case Decl::AccessSpec: case Decl::CXXMethod: case Decl::Field: case Decl::StaticAssert: case Decl::TypeAlias: case Decl::Typedef: return true; } } void ODRHash::AddSubDecl(const Decl *D) { assert(D && "Expecting non-null pointer."); AddDecl(D); ODRDeclVisitor(ID, *this).Visit(D); } void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) { assert(Record && Record->hasDefinition() && "Expected non-null record to be a definition."); if (isa(Record)) { return; } AddDecl(Record); // Filter out sub-Decls which will not be processed in order to get an // accurate count of Decl's. llvm::SmallVector Decls; for (const Decl *SubDecl : Record->decls()) { if (isWhitelistedDecl(SubDecl, Record)) { Decls.push_back(SubDecl); } } ID.AddInteger(Decls.size()); for (auto SubDecl : Decls) { AddSubDecl(SubDecl); } } void ODRHash::AddDecl(const Decl *D) { assert(D && "Expecting non-null pointer."); auto Result = DeclMap.insert(std::make_pair(D, DeclMap.size())); ID.AddInteger(Result.first->second); // On first encounter of a Decl pointer, process it. Every time afterwards, // only the index value is needed. if (!Result.second) { return; } ID.AddInteger(D->getKind()); if (const NamedDecl *ND = dyn_cast(D)) { AddDeclarationName(ND->getDeclName()); } } // Process a Type pointer. Add* methods call back into ODRHash while Visit* // methods process the relevant parts of the Type. class ODRTypeVisitor : public TypeVisitor { typedef TypeVisitor Inherited; llvm::FoldingSetNodeID &ID; ODRHash &Hash; public: ODRTypeVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash) : ID(ID), Hash(Hash) {} void AddStmt(Stmt *S) { Hash.AddBoolean(S); if (S) { Hash.AddStmt(S); } } void AddDecl(Decl *D) { Hash.AddBoolean(D); if (D) { Hash.AddDecl(D); } } void AddQualType(QualType T) { Hash.AddQualType(T); } + void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { + Hash.AddBoolean(NNS); + if (NNS) { + Hash.AddNestedNameSpecifier(NNS); + } + } + + void AddIdentifierInfo(const IdentifierInfo *II) { + Hash.AddBoolean(II); + if (II) { + Hash.AddIdentifierInfo(II); + } + } + void VisitQualifiers(Qualifiers Quals) { ID.AddInteger(Quals.getAsOpaqueValue()); } void Visit(const Type *T) { ID.AddInteger(T->getTypeClass()); Inherited::Visit(T); } void VisitType(const Type *T) {} void VisitAdjustedType(const AdjustedType *T) { AddQualType(T->getOriginalType()); AddQualType(T->getAdjustedType()); VisitType(T); } void VisitDecayedType(const DecayedType *T) { AddQualType(T->getDecayedType()); AddQualType(T->getPointeeType()); VisitAdjustedType(T); } void VisitArrayType(const ArrayType *T) { AddQualType(T->getElementType()); ID.AddInteger(T->getSizeModifier()); VisitQualifiers(T->getIndexTypeQualifiers()); VisitType(T); } void VisitConstantArrayType(const ConstantArrayType *T) { T->getSize().Profile(ID); VisitArrayType(T); } void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { AddStmt(T->getSizeExpr()); VisitArrayType(T); } void VisitIncompleteArrayType(const IncompleteArrayType *T) { VisitArrayType(T); } void VisitVariableArrayType(const VariableArrayType *T) { AddStmt(T->getSizeExpr()); VisitArrayType(T); } void VisitBuiltinType(const BuiltinType *T) { ID.AddInteger(T->getKind()); VisitType(T); } void VisitFunctionType(const FunctionType *T) { AddQualType(T->getReturnType()); T->getExtInfo().Profile(ID); Hash.AddBoolean(T->isConst()); Hash.AddBoolean(T->isVolatile()); Hash.AddBoolean(T->isRestrict()); VisitType(T); } void VisitFunctionNoProtoType(const FunctionNoProtoType *T) { VisitFunctionType(T); } void VisitFunctionProtoType(const FunctionProtoType *T) { ID.AddInteger(T->getNumParams()); for (auto ParamType : T->getParamTypes()) AddQualType(ParamType); VisitFunctionType(T); } void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); AddQualType(T->getDecl()->getUnderlyingType().getCanonicalType()); VisitType(T); + } + + void VisitTagType(const TagType *T) { + AddDecl(T->getDecl()); + VisitType(T); + } + + void VisitRecordType(const RecordType *T) { VisitTagType(T); } + void VisitEnumType(const EnumType *T) { VisitTagType(T); } + + void VisitTypeWithKeyword(const TypeWithKeyword *T) { + ID.AddInteger(T->getKeyword()); + VisitType(T); + }; + + void VisitDependentNameType(const DependentNameType *T) { + AddNestedNameSpecifier(T->getQualifier()); + AddIdentifierInfo(T->getIdentifier()); + VisitTypeWithKeyword(T); + } + + void VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType *T) { + AddIdentifierInfo(T->getIdentifier()); + AddNestedNameSpecifier(T->getQualifier()); + ID.AddInteger(T->getNumArgs()); + for (const auto &TA : T->template_arguments()) { + Hash.AddTemplateArgument(TA); + } + VisitTypeWithKeyword(T); + } + + void VisitElaboratedType(const ElaboratedType *T) { + AddNestedNameSpecifier(T->getQualifier()); + AddQualType(T->getNamedType()); + VisitTypeWithKeyword(T); } }; void ODRHash::AddType(const Type *T) { assert(T && "Expecting non-null pointer."); auto Result = TypeMap.insert(std::make_pair(T, TypeMap.size())); ID.AddInteger(Result.first->second); // On first encounter of a Type pointer, process it. Every time afterwards, // only the index value is needed. if (!Result.second) { return; } ODRTypeVisitor(ID, *this).Visit(T); } void ODRHash::AddQualType(QualType T) { AddBoolean(T.isNull()); if (T.isNull()) return; SplitQualType split = T.split(); ID.AddInteger(split.Quals.getAsOpaqueValue()); AddType(split.Ty); } void ODRHash::AddBoolean(bool Value) { Bools.push_back(Value); } Index: vendor/clang/dist/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- vendor/clang/dist/lib/CodeGen/CGDebugInfo.cpp (revision 318415) +++ vendor/clang/dist/lib/CodeGen/CGDebugInfo.cpp (revision 318416) @@ -1,4121 +1,4121 @@ //===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This coordinates the debug information generation while generating code. // //===----------------------------------------------------------------------===// #include "CGDebugInfo.h" #include "CGBlocks.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PreprocessorOptions.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" #include "llvm/Support/Path.h" using namespace clang; using namespace clang::CodeGen; static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) { auto TI = Ctx.getTypeInfo(Ty); return TI.AlignIsRequired ? TI.Align : 0; } static uint32_t getTypeAlignIfRequired(QualType Ty, const ASTContext &Ctx) { return getTypeAlignIfRequired(Ty.getTypePtr(), Ctx); } static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) { return D->hasAttr() ? D->getMaxAlignment() : 0; } CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()), DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs), DBuilder(CGM.getModule()) { for (const auto &KV : CGM.getCodeGenOpts().DebugPrefixMap) DebugPrefixMap[KV.first] = KV.second; CreateCompileUnit(); } CGDebugInfo::~CGDebugInfo() { assert(LexicalBlockStack.empty() && "Region stack mismatch, stack not empty!"); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation) : CGF(&CGF) { init(TemporaryLocation); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, bool DefaultToEmpty, SourceLocation TemporaryLocation) : CGF(&CGF) { init(TemporaryLocation, DefaultToEmpty); } void ApplyDebugLocation::init(SourceLocation TemporaryLocation, bool DefaultToEmpty) { auto *DI = CGF->getDebugInfo(); if (!DI) { CGF = nullptr; return; } OriginalLocation = CGF->Builder.getCurrentDebugLocation(); if (TemporaryLocation.isValid()) { DI->EmitLocation(CGF->Builder, TemporaryLocation); return; } if (DefaultToEmpty) { CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc()); return; } // Construct a location that has a valid scope, but no line info. assert(!DI->LexicalBlockStack.empty()); CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc::get( 0, 0, DI->LexicalBlockStack.back(), DI->getInlinedAt())); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E) : CGF(&CGF) { init(E->getExprLoc()); } ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc) : CGF(&CGF) { if (!CGF.getDebugInfo()) { this->CGF = nullptr; return; } OriginalLocation = CGF.Builder.getCurrentDebugLocation(); if (Loc) CGF.Builder.SetCurrentDebugLocation(std::move(Loc)); } ApplyDebugLocation::~ApplyDebugLocation() { // Query CGF so the location isn't overwritten when location updates are // temporarily disabled (for C++ default function arguments) if (CGF) CGF->Builder.SetCurrentDebugLocation(std::move(OriginalLocation)); } ApplyInlineDebugLocation::ApplyInlineDebugLocation(CodeGenFunction &CGF, GlobalDecl InlinedFn) : CGF(&CGF) { if (!CGF.getDebugInfo()) { this->CGF = nullptr; return; } auto &DI = *CGF.getDebugInfo(); SavedLocation = DI.getLocation(); assert((DI.getInlinedAt() == CGF.Builder.getCurrentDebugLocation()->getInlinedAt()) && "CGDebugInfo and IRBuilder are out of sync"); DI.EmitInlineFunctionStart(CGF.Builder, InlinedFn); } ApplyInlineDebugLocation::~ApplyInlineDebugLocation() { if (!CGF) return; auto &DI = *CGF->getDebugInfo(); DI.EmitInlineFunctionEnd(CGF->Builder); DI.EmitLocation(CGF->Builder, SavedLocation); } void CGDebugInfo::setLocation(SourceLocation Loc) { // If the new location isn't valid return. if (Loc.isInvalid()) return; CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc); // If we've changed files in the middle of a lexical scope go ahead // and create a new lexical scope with file node if it's different // from the one in the scope. if (LexicalBlockStack.empty()) return; SourceManager &SM = CGM.getContext().getSourceManager(); auto *Scope = cast(LexicalBlockStack.back()); PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc); if (PCLoc.isInvalid() || Scope->getFilename() == PCLoc.getFilename()) return; if (auto *LBF = dyn_cast(Scope)) { LexicalBlockStack.pop_back(); LexicalBlockStack.emplace_back(DBuilder.createLexicalBlockFile( LBF->getScope(), getOrCreateFile(CurLoc))); } else if (isa(Scope) || isa(Scope)) { LexicalBlockStack.pop_back(); LexicalBlockStack.emplace_back( DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc))); } } llvm::DIScope *CGDebugInfo::getDeclContextDescriptor(const Decl *D) { llvm::DIScope *Mod = getParentModuleOrNull(D); return getContextDescriptor(cast(D->getDeclContext()), Mod ? Mod : TheCU); } llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context, llvm::DIScope *Default) { if (!Context) return Default; auto I = RegionMap.find(Context); if (I != RegionMap.end()) { llvm::Metadata *V = I->second; return dyn_cast_or_null(V); } // Check namespace. if (const auto *NSDecl = dyn_cast(Context)) return getOrCreateNamespace(NSDecl); if (const auto *RDecl = dyn_cast(Context)) if (!RDecl->isDependentType()) return getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), getOrCreateMainFile()); return Default; } StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { assert(FD && "Invalid FunctionDecl!"); IdentifierInfo *FII = FD->getIdentifier(); FunctionTemplateSpecializationInfo *Info = FD->getTemplateSpecializationInfo(); // Emit the unqualified name in normal operation. LLVM and the debugger can // compute the fully qualified name from the scope chain. If we're only // emitting line table info, there won't be any scope chains, so emit the // fully qualified name here so that stack traces are more accurate. // FIXME: Do this when emitting DWARF as well as when emitting CodeView after // evaluating the size impact. bool UseQualifiedName = DebugKind == codegenoptions::DebugLineTablesOnly && CGM.getCodeGenOpts().EmitCodeView; if (!Info && FII && !UseQualifiedName) return FII->getName(); SmallString<128> NS; llvm::raw_svector_ostream OS(NS); PrintingPolicy Policy(CGM.getLangOpts()); Policy.MSVCFormatting = CGM.getCodeGenOpts().EmitCodeView; if (!UseQualifiedName) FD->printName(OS); else FD->printQualifiedName(OS, Policy); // Add any template specialization args. if (Info) { const TemplateArgumentList *TArgs = Info->TemplateArguments; TemplateSpecializationType::PrintTemplateArgumentList(OS, TArgs->asArray(), Policy); } // Copy this name on the side and use its reference. return internString(OS.str()); } StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { SmallString<256> MethodName; llvm::raw_svector_ostream OS(MethodName); OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; const DeclContext *DC = OMD->getDeclContext(); if (const auto *OID = dyn_cast(DC)) { OS << OID->getName(); } else if (const auto *OID = dyn_cast(DC)) { OS << OID->getName(); } else if (const auto *OC = dyn_cast(DC)) { if (OC->IsClassExtension()) { OS << OC->getClassInterface()->getName(); } else { OS << OC->getIdentifier()->getNameStart() << '(' << OC->getIdentifier()->getNameStart() << ')'; } } else if (const auto *OCD = dyn_cast(DC)) { OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')'; } else if (isa(DC)) { // We can extract the type of the class from the self pointer. if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) { QualType ClassTy = cast(SelfDecl->getType())->getPointeeType(); ClassTy.print(OS, PrintingPolicy(LangOptions())); } } OS << ' ' << OMD->getSelector().getAsString() << ']'; return internString(OS.str()); } StringRef CGDebugInfo::getSelectorName(Selector S) { return internString(S.getAsString()); } StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { if (isa(RD)) { SmallString<128> Name; llvm::raw_svector_ostream OS(Name); RD->getNameForDiagnostic(OS, CGM.getContext().getPrintingPolicy(), /*Qualified*/ false); // Copy this name on the side and use its reference. return internString(Name); } // quick optimization to avoid having to intern strings that are already // stored reliably elsewhere if (const IdentifierInfo *II = RD->getIdentifier()) return II->getName(); // The CodeView printer in LLVM wants to see the names of unnamed types: it is // used to reconstruct the fully qualified type names. if (CGM.getCodeGenOpts().EmitCodeView) { if (const TypedefNameDecl *D = RD->getTypedefNameForAnonDecl()) { assert(RD->getDeclContext() == D->getDeclContext() && "Typedef should not be in another decl context!"); assert(D->getDeclName().getAsIdentifierInfo() && "Typedef was not named!"); return D->getDeclName().getAsIdentifierInfo()->getName(); } if (CGM.getLangOpts().CPlusPlus) { StringRef Name; ASTContext &Context = CGM.getContext(); if (const DeclaratorDecl *DD = Context.getDeclaratorForUnnamedTagDecl(RD)) // Anonymous types without a name for linkage purposes have their // declarator mangled in if they have one. Name = DD->getName(); else if (const TypedefNameDecl *TND = Context.getTypedefNameForUnnamedTagDecl(RD)) // Anonymous types without a name for linkage purposes have their // associate typedef mangled in if they have one. Name = TND->getName(); if (!Name.empty()) { SmallString<256> UnnamedType(" &Checksum) const { Checksum.clear(); if (!CGM.getCodeGenOpts().EmitCodeView) return llvm::DIFile::CSK_None; SourceManager &SM = CGM.getContext().getSourceManager(); bool Invalid; llvm::MemoryBuffer *MemBuffer = SM.getBuffer(FID, &Invalid); if (Invalid) return llvm::DIFile::CSK_None; llvm::MD5 Hash; llvm::MD5::MD5Result Result; Hash.update(MemBuffer->getBuffer()); Hash.final(Result); Hash.stringifyResult(Result, Checksum); return llvm::DIFile::CSK_MD5; } llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { if (!Loc.isValid()) // If Location is not valid then use main input file. return DBuilder.createFile(remapDIPath(TheCU->getFilename()), remapDIPath(TheCU->getDirectory()), TheCU->getFile()->getChecksumKind(), TheCU->getFile()->getChecksum()); SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc); if (PLoc.isInvalid() || StringRef(PLoc.getFilename()).empty()) // If the location is not valid then use main input file. return DBuilder.createFile(remapDIPath(TheCU->getFilename()), remapDIPath(TheCU->getDirectory()), TheCU->getFile()->getChecksumKind(), TheCU->getFile()->getChecksum()); // Cache the results. const char *fname = PLoc.getFilename(); auto it = DIFileCache.find(fname); if (it != DIFileCache.end()) { // Verify that the information still exists. if (llvm::Metadata *V = it->second) return cast(V); } SmallString<32> Checksum; llvm::DIFile::ChecksumKind CSKind = computeChecksum(SM.getFileID(Loc), Checksum); llvm::DIFile *F = DBuilder.createFile(remapDIPath(PLoc.getFilename()), remapDIPath(getCurrentDirname()), CSKind, Checksum); DIFileCache[fname].reset(F); return F; } llvm::DIFile *CGDebugInfo::getOrCreateMainFile() { return DBuilder.createFile(remapDIPath(TheCU->getFilename()), remapDIPath(TheCU->getDirectory()), TheCU->getFile()->getChecksumKind(), TheCU->getFile()->getChecksum()); } std::string CGDebugInfo::remapDIPath(StringRef Path) const { for (const auto &Entry : DebugPrefixMap) if (Path.startswith(Entry.first)) return (Twine(Entry.second) + Path.substr(Entry.first.size())).str(); return Path.str(); } unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { if (Loc.isInvalid() && CurLoc.isInvalid()) return 0; SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); return PLoc.isValid() ? PLoc.getLine() : 0; } unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) { // We may not want column information at all. if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo) return 0; // If the location is invalid then use the current column. if (Loc.isInvalid() && CurLoc.isInvalid()) return 0; SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); return PLoc.isValid() ? PLoc.getColumn() : 0; } StringRef CGDebugInfo::getCurrentDirname() { if (!CGM.getCodeGenOpts().DebugCompilationDir.empty()) return CGM.getCodeGenOpts().DebugCompilationDir; if (!CWDName.empty()) return CWDName; SmallString<256> CWD; llvm::sys::fs::current_path(CWD); return CWDName = internString(CWD); } void CGDebugInfo::CreateCompileUnit() { SmallString<32> Checksum; llvm::DIFile::ChecksumKind CSKind = llvm::DIFile::CSK_None; // Should we be asking the SourceManager for the main file name, instead of // accepting it as an argument? This just causes the main file name to // mismatch with source locations and create extra lexical scopes or // mismatched debug info (a CU with a DW_AT_file of "-", because that's what // the driver passed, but functions/other things have DW_AT_file of "" // because that's what the SourceManager says) // Get absolute path name. SourceManager &SM = CGM.getContext().getSourceManager(); std::string MainFileName = CGM.getCodeGenOpts().MainFileName; if (MainFileName.empty()) MainFileName = ""; // The main file name provided via the "-main-file-name" option contains just // the file name itself with no path information. This file name may have had // a relative path, so we look into the actual file entry for the main // file to determine the real absolute path for the file. std::string MainFileDir; if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { MainFileDir = remapDIPath(MainFile->getDir()->getName()); if (MainFileDir != ".") { llvm::SmallString<1024> MainFileDirSS(MainFileDir); llvm::sys::path::append(MainFileDirSS, MainFileName); MainFileName = MainFileDirSS.str(); } CSKind = computeChecksum(SM.getMainFileID(), Checksum); } llvm::dwarf::SourceLanguage LangTag; const LangOptions &LO = CGM.getLangOpts(); if (LO.CPlusPlus) { if (LO.ObjC1) LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus; else LangTag = llvm::dwarf::DW_LANG_C_plus_plus; } else if (LO.ObjC1) { LangTag = llvm::dwarf::DW_LANG_ObjC; } else if (LO.RenderScript) { LangTag = llvm::dwarf::DW_LANG_GOOGLE_RenderScript; } else if (LO.C99) { LangTag = llvm::dwarf::DW_LANG_C99; } else { LangTag = llvm::dwarf::DW_LANG_C89; } std::string Producer = getClangFullVersion(); // Figure out which version of the ObjC runtime we have. unsigned RuntimeVers = 0; if (LO.ObjC1) RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1; llvm::DICompileUnit::DebugEmissionKind EmissionKind; switch (DebugKind) { case codegenoptions::NoDebugInfo: case codegenoptions::LocTrackingOnly: EmissionKind = llvm::DICompileUnit::NoDebug; break; case codegenoptions::DebugLineTablesOnly: EmissionKind = llvm::DICompileUnit::LineTablesOnly; break; case codegenoptions::LimitedDebugInfo: case codegenoptions::FullDebugInfo: EmissionKind = llvm::DICompileUnit::FullDebug; break; } // Create new compile unit. // FIXME - Eliminate TheCU. TheCU = DBuilder.createCompileUnit( LangTag, DBuilder.createFile(remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSKind, Checksum), Producer, LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers, CGM.getCodeGenOpts().EnableSplitDwarf ? "" : CGM.getCodeGenOpts().SplitDwarfFile, EmissionKind, 0 /* DWOid */, CGM.getCodeGenOpts().SplitDwarfInlining, CGM.getCodeGenOpts().DebugInfoForProfiling); } llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { llvm::dwarf::TypeKind Encoding; StringRef BTName; switch (BT->getKind()) { #define BUILTIN_TYPE(Id, SingletonId) #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: #include "clang/AST/BuiltinTypes.def" case BuiltinType::Dependent: llvm_unreachable("Unexpected builtin type"); case BuiltinType::NullPtr: return DBuilder.createNullPtrType(); case BuiltinType::Void: return nullptr; case BuiltinType::ObjCClass: if (!ClassTy) ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, "objc_class", TheCU, getOrCreateMainFile(), 0); return ClassTy; case BuiltinType::ObjCId: { // typedef struct objc_class *Class; // typedef struct objc_object { // Class isa; // } *id; if (ObjTy) return ObjTy; if (!ClassTy) ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, "objc_class", TheCU, getOrCreateMainFile(), 0); unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); auto *ISATy = DBuilder.createPointerType(ClassTy, Size); ObjTy = DBuilder.createStructType( TheCU, "objc_object", getOrCreateMainFile(), 0, 0, 0, llvm::DINode::FlagZero, nullptr, llvm::DINodeArray()); DBuilder.replaceArrays( ObjTy, DBuilder.getOrCreateArray(&*DBuilder.createMemberType( ObjTy, "isa", getOrCreateMainFile(), 0, Size, 0, 0, llvm::DINode::FlagZero, ISATy))); return ObjTy; } case BuiltinType::ObjCSel: { if (!SelTy) SelTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, "objc_selector", TheCU, getOrCreateMainFile(), 0); return SelTy; } #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: \ return getOrCreateStructPtrType("opencl_" #ImgType "_" #Suffix "_t", \ SingletonId); #include "clang/Basic/OpenCLImageTypes.def" case BuiltinType::OCLSampler: return getOrCreateStructPtrType("opencl_sampler_t", OCLSamplerDITy); case BuiltinType::OCLEvent: return getOrCreateStructPtrType("opencl_event_t", OCLEventDITy); case BuiltinType::OCLClkEvent: return getOrCreateStructPtrType("opencl_clk_event_t", OCLClkEventDITy); case BuiltinType::OCLQueue: return getOrCreateStructPtrType("opencl_queue_t", OCLQueueDITy); case BuiltinType::OCLReserveID: return getOrCreateStructPtrType("opencl_reserve_id_t", OCLReserveIDDITy); case BuiltinType::UChar: case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break; case BuiltinType::Char_S: case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break; case BuiltinType::Char16: case BuiltinType::Char32: Encoding = llvm::dwarf::DW_ATE_UTF; break; case BuiltinType::UShort: case BuiltinType::UInt: case BuiltinType::UInt128: case BuiltinType::ULong: case BuiltinType::WChar_U: case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break; case BuiltinType::Short: case BuiltinType::Int: case BuiltinType::Int128: case BuiltinType::Long: case BuiltinType::WChar_S: case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break; case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break; case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::LongDouble: case BuiltinType::Float128: case BuiltinType::Double: // FIXME: For targets where long double and __float128 have the same size, // they are currently indistinguishable in the debugger without some // special treatment. However, there is currently no consensus on encoding // and this should be updated once a DWARF encoding exists for distinct // floating point types of the same size. Encoding = llvm::dwarf::DW_ATE_float; break; } switch (BT->getKind()) { case BuiltinType::Long: BTName = "long int"; break; case BuiltinType::LongLong: BTName = "long long int"; break; case BuiltinType::ULong: BTName = "long unsigned int"; break; case BuiltinType::ULongLong: BTName = "long long unsigned int"; break; default: BTName = BT->getName(CGM.getLangOpts()); break; } // Bit size and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(BT); return DBuilder.createBasicType(BTName, Size, Encoding); } llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) { // Bit size and offset of the type. llvm::dwarf::TypeKind Encoding = llvm::dwarf::DW_ATE_complex_float; if (Ty->isComplexIntegerType()) Encoding = llvm::dwarf::DW_ATE_lo_user; uint64_t Size = CGM.getContext().getTypeSize(Ty); return DBuilder.createBasicType("complex", Size, Encoding); } llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile *Unit) { QualifierCollector Qc; const Type *T = Qc.strip(Ty); // Ignore these qualifiers for now. Qc.removeObjCGCAttr(); Qc.removeAddressSpace(); Qc.removeObjCLifetime(); // We will create one Derived type for one qualifier and recurse to handle any // additional ones. llvm::dwarf::Tag Tag; if (Qc.hasConst()) { Tag = llvm::dwarf::DW_TAG_const_type; Qc.removeConst(); } else if (Qc.hasVolatile()) { Tag = llvm::dwarf::DW_TAG_volatile_type; Qc.removeVolatile(); } else if (Qc.hasRestrict()) { Tag = llvm::dwarf::DW_TAG_restrict_type; Qc.removeRestrict(); } else { assert(Qc.empty() && "Unknown type qualifier for debug info"); return getOrCreateType(QualType(T, 0), Unit); } auto *FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit); // No need to fill in the Name, Line, Size, Alignment, Offset in case of // CVR derived types. return DBuilder.createQualifiedType(Tag, FromTy); } llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, llvm::DIFile *Unit) { // The frontend treats 'id' as a typedef to an ObjCObjectType, // whereas 'id' is treated as an ObjCPointerType. For the // debug info, we want to emit 'id' in both cases. if (Ty->isObjCQualifiedIdType()) return getOrCreateType(CGM.getContext().getObjCIdType(), Unit); return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, Ty->getPointeeType(), Unit); } llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, llvm::DIFile *Unit) { return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, Ty->getPointeeType(), Unit); } /// \return whether a C++ mangling exists for the type defined by TD. static bool hasCXXMangling(const TagDecl *TD, llvm::DICompileUnit *TheCU) { switch (TheCU->getSourceLanguage()) { case llvm::dwarf::DW_LANG_C_plus_plus: return true; case llvm::dwarf::DW_LANG_ObjC_plus_plus: return isa(TD) || isa(TD); default: return false; } } /// In C++ mode, types have linkage, so we can rely on the ODR and /// on their mangled names, if they're external. static SmallString<256> getUniqueTagTypeName(const TagType *Ty, CodeGenModule &CGM, llvm::DICompileUnit *TheCU) { SmallString<256> FullName; const TagDecl *TD = Ty->getDecl(); if (!hasCXXMangling(TD, TheCU) || !TD->isExternallyVisible()) return FullName; // TODO: This is using the RTTI name. Is there a better way to get // a unique string for a type? llvm::raw_svector_ostream Out(FullName); CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(QualType(Ty, 0), Out); return FullName; } /// \return the approproate DWARF tag for a composite type. static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) { llvm::dwarf::Tag Tag; if (RD->isStruct() || RD->isInterface()) Tag = llvm::dwarf::DW_TAG_structure_type; else if (RD->isUnion()) Tag = llvm::dwarf::DW_TAG_union_type; else { // FIXME: This could be a struct type giving a default visibility different // than C++ class type, but needs llvm metadata changes first. assert(RD->isClass()); Tag = llvm::dwarf::DW_TAG_class_type; } return Tag; } llvm::DICompositeType * CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty, llvm::DIScope *Ctx) { const RecordDecl *RD = Ty->getDecl(); if (llvm::DIType *T = getTypeOrNull(CGM.getContext().getRecordType(RD))) return cast(T); llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation()); unsigned Line = getLineNumber(RD->getLocation()); StringRef RDName = getClassName(RD); uint64_t Size = 0; uint32_t Align = 0; // Create the type. SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU); llvm::DICompositeType *RetTy = DBuilder.createReplaceableCompositeType( getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align, llvm::DINode::FlagFwdDecl, FullName); ReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(Ty), std::make_tuple(static_cast(RetTy))); return RetTy; } llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, QualType PointeeTy, llvm::DIFile *Unit) { // Bit size, align and offset of the type. // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(PointeeTy); uint64_t Size = CGM.getTarget().getPointerWidth(AddressSpace); auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); if (Tag == llvm::dwarf::DW_TAG_reference_type || Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit), Size, Align, DWARFAddressSpace); else return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size, Align, DWARFAddressSpace); } llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache) { if (Cache) return Cache; Cache = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, Name, TheCU, getOrCreateMainFile(), 0); unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); Cache = DBuilder.createPointerType(Cache, Size); return Cache; } llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIFile *Unit) { SmallVector EltTys; QualType FType; uint64_t FieldSize, FieldOffset; uint32_t FieldAlign; llvm::DINodeArray Elements; FieldOffset = 0; FType = CGM.getContext().UnsignedLongTy; EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset)); EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset)); Elements = DBuilder.getOrCreateArray(EltTys); EltTys.clear(); llvm::DINode::DIFlags Flags = llvm::DINode::FlagAppleBlock; unsigned LineNo = 0; auto *EltTy = DBuilder.createStructType(Unit, "__block_descriptor", nullptr, LineNo, FieldOffset, 0, Flags, nullptr, Elements); // Bit size, align and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(Ty); auto *DescTy = DBuilder.createPointerType(EltTy, Size); FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); FType = CGM.getContext().IntTy; EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset)); FType = CGM.getContext().getPointerType(Ty->getPointeeType()); EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset)); FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldSize = CGM.getContext().getTypeSize(Ty); FieldAlign = CGM.getContext().getTypeAlign(Ty); EltTys.push_back(DBuilder.createMemberType( Unit, "__descriptor", nullptr, LineNo, FieldSize, FieldAlign, FieldOffset, llvm::DINode::FlagZero, DescTy)); FieldOffset += FieldSize; Elements = DBuilder.getOrCreateArray(EltTys); // The __block_literal_generic structs are marked with a special // DW_AT_APPLE_BLOCK attribute and are an implementation detail only // the debugger needs to know about. To allow type uniquing, emit // them without a name or a location. EltTy = DBuilder.createStructType(Unit, "", nullptr, LineNo, FieldOffset, 0, Flags, nullptr, Elements); return DBuilder.createPointerType(EltTy, Size); } llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, llvm::DIFile *Unit) { assert(Ty->isTypeAlias()); llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit); SmallString<128> NS; llvm::raw_svector_ostream OS(NS); Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy(), /*qualified*/ false); TemplateSpecializationType::PrintTemplateArgumentList( OS, Ty->template_arguments(), CGM.getContext().getPrintingPolicy()); auto *AliasDecl = cast( Ty->getTemplateName().getAsTemplateDecl())->getTemplatedDecl(); SourceLocation Loc = AliasDecl->getLocation(); return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc), getLineNumber(Loc), getDeclContextDescriptor(AliasDecl)); } llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile *Unit) { // We don't set size information, but do specify where the typedef was // declared. SourceLocation Loc = Ty->getDecl()->getLocation(); // Typedefs are derived from some other type. return DBuilder.createTypedef( getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit), Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc), getDeclContextDescriptor(Ty->getDecl())); } static unsigned getDwarfCC(CallingConv CC) { switch (CC) { case CC_C: // Avoid emitting DW_AT_calling_convention if the C convention was used. return 0; case CC_X86StdCall: return llvm::dwarf::DW_CC_BORLAND_stdcall; case CC_X86FastCall: return llvm::dwarf::DW_CC_BORLAND_msfastcall; case CC_X86ThisCall: return llvm::dwarf::DW_CC_BORLAND_thiscall; case CC_X86VectorCall: return llvm::dwarf::DW_CC_LLVM_vectorcall; case CC_X86Pascal: return llvm::dwarf::DW_CC_BORLAND_pascal; // FIXME: Create new DW_CC_ codes for these calling conventions. case CC_X86_64Win64: case CC_X86_64SysV: case CC_AAPCS: case CC_AAPCS_VFP: case CC_IntelOclBicc: case CC_SpirFunction: case CC_OpenCLKernel: case CC_Swift: case CC_PreserveMost: case CC_PreserveAll: case CC_X86RegCall: return 0; } return 0; } llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty, llvm::DIFile *Unit) { SmallVector EltTys; // Add the result type at least. EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit)); // Set up remainder of arguments if there is a prototype. // otherwise emit it as a variadic function. if (isa(Ty)) EltTys.push_back(DBuilder.createUnspecifiedParameter()); else if (const auto *FPT = dyn_cast(Ty)) { for (const QualType &ParamType : FPT->param_types()) EltTys.push_back(getOrCreateType(ParamType, Unit)); if (FPT->isVariadic()) EltTys.push_back(DBuilder.createUnspecifiedParameter()); } llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys); return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero, getDwarfCC(Ty->getCallConv())); } /// Convert an AccessSpecifier into the corresponding DINode flag. /// As an optimization, return 0 if the access specifier equals the /// default for the containing type. static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access, const RecordDecl *RD) { AccessSpecifier Default = clang::AS_none; if (RD && RD->isClass()) Default = clang::AS_private; else if (RD && (RD->isStruct() || RD->isUnion())) Default = clang::AS_public; if (Access == Default) return llvm::DINode::FlagZero; switch (Access) { case clang::AS_private: return llvm::DINode::FlagPrivate; case clang::AS_protected: return llvm::DINode::FlagProtected; case clang::AS_public: return llvm::DINode::FlagPublic; case clang::AS_none: return llvm::DINode::FlagZero; } llvm_unreachable("unexpected access enumerator"); } llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, llvm::DIScope *RecordTy, const RecordDecl *RD) { StringRef Name = BitFieldDecl->getName(); QualType Ty = BitFieldDecl->getType(); SourceLocation Loc = BitFieldDecl->getLocation(); llvm::DIFile *VUnit = getOrCreateFile(Loc); llvm::DIType *DebugType = getOrCreateType(Ty, VUnit); // Get the location for the field. llvm::DIFile *File = getOrCreateFile(Loc); unsigned Line = getLineNumber(Loc); const CGBitFieldInfo &BitFieldInfo = CGM.getTypes().getCGRecordLayout(RD).getBitFieldInfo(BitFieldDecl); uint64_t SizeInBits = BitFieldInfo.Size; assert(SizeInBits > 0 && "found named 0-width bitfield"); uint64_t StorageOffsetInBits = CGM.getContext().toBits(BitFieldInfo.StorageOffset); uint64_t OffsetInBits = StorageOffsetInBits + BitFieldInfo.Offset; llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD); return DBuilder.createBitFieldMemberType( RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits, Flags, DebugType); } llvm::DIType * CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, llvm::DIScope *scope, const RecordDecl *RD) { llvm::DIType *debugType = getOrCreateType(type, tunit); // Get the location for the field. llvm::DIFile *file = getOrCreateFile(loc); unsigned line = getLineNumber(loc); uint64_t SizeInBits = 0; auto Align = AlignInBits; if (!type->isIncompleteArrayType()) { TypeInfo TI = CGM.getContext().getTypeInfo(type); SizeInBits = TI.Width; if (!Align) Align = getTypeAlignIfRequired(type, CGM.getContext()); } llvm::DINode::DIFlags flags = getAccessFlag(AS, RD); return DBuilder.createMemberType(scope, name, file, line, SizeInBits, Align, offsetInBits, flags, debugType); } void CGDebugInfo::CollectRecordLambdaFields( const CXXRecordDecl *CXXDecl, SmallVectorImpl &elements, llvm::DIType *RecordTy) { // For C++11 Lambdas a Field will be the same as a Capture, but the Capture // has the name and the location of the variable so we should iterate over // both concurrently. const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(CXXDecl); RecordDecl::field_iterator Field = CXXDecl->field_begin(); unsigned fieldno = 0; for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(), E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) { const LambdaCapture &C = *I; if (C.capturesVariable()) { SourceLocation Loc = C.getLocation(); assert(!Field->isBitField() && "lambdas don't have bitfield members!"); VarDecl *V = C.getCapturedVar(); StringRef VName = V->getName(); llvm::DIFile *VUnit = getOrCreateFile(Loc); auto Align = getDeclAlignIfRequired(V, CGM.getContext()); llvm::DIType *FieldType = createFieldType( VName, Field->getType(), Loc, Field->getAccess(), layout.getFieldOffset(fieldno), Align, VUnit, RecordTy, CXXDecl); elements.push_back(FieldType); } else if (C.capturesThis()) { // TODO: Need to handle 'this' in some way by probably renaming the // this of the lambda class and having a field member of 'this' or // by using AT_object_pointer for the function and having that be // used as 'this' for semantic references. FieldDecl *f = *Field; llvm::DIFile *VUnit = getOrCreateFile(f->getLocation()); QualType type = f->getType(); llvm::DIType *fieldType = createFieldType( "this", type, f->getLocation(), f->getAccess(), layout.getFieldOffset(fieldno), VUnit, RecordTy, CXXDecl); elements.push_back(fieldType); } } } llvm::DIDerivedType * CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, const RecordDecl *RD) { // Create the descriptor for the static variable, with or without // constant initializers. Var = Var->getCanonicalDecl(); llvm::DIFile *VUnit = getOrCreateFile(Var->getLocation()); llvm::DIType *VTy = getOrCreateType(Var->getType(), VUnit); unsigned LineNumber = getLineNumber(Var->getLocation()); StringRef VName = Var->getName(); llvm::Constant *C = nullptr; if (Var->getInit()) { const APValue *Value = Var->evaluateValue(); if (Value) { if (Value->isInt()) C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); if (Value->isFloat()) C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat()); } } llvm::DINode::DIFlags Flags = getAccessFlag(Var->getAccess(), RD); auto Align = getDeclAlignIfRequired(Var, CGM.getContext()); llvm::DIDerivedType *GV = DBuilder.createStaticMemberType( RecordTy, VName, VUnit, LineNumber, VTy, Flags, C, Align); StaticDataMemberCache[Var->getCanonicalDecl()].reset(GV); return GV; } void CGDebugInfo::CollectRecordNormalField( const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile *tunit, SmallVectorImpl &elements, llvm::DIType *RecordTy, const RecordDecl *RD) { StringRef name = field->getName(); QualType type = field->getType(); // Ignore unnamed fields unless they're anonymous structs/unions. if (name.empty() && !type->isRecordType()) return; llvm::DIType *FieldType; if (field->isBitField()) { FieldType = createBitFieldType(field, RecordTy, RD); } else { auto Align = getDeclAlignIfRequired(field, CGM.getContext()); FieldType = createFieldType(name, type, field->getLocation(), field->getAccess(), OffsetInBits, Align, tunit, RecordTy, RD); } elements.push_back(FieldType); } void CGDebugInfo::CollectRecordNestedRecord( const RecordDecl *RD, SmallVectorImpl &elements) { QualType Ty = CGM.getContext().getTypeDeclType(RD); // Injected class names are not considered nested records. if (isa(Ty)) return; SourceLocation Loc = RD->getLocation(); llvm::DIType *nestedType = getOrCreateType(Ty, getOrCreateFile(Loc)); elements.push_back(nestedType); } void CGDebugInfo::CollectRecordFields( const RecordDecl *record, llvm::DIFile *tunit, SmallVectorImpl &elements, llvm::DICompositeType *RecordTy) { const auto *CXXDecl = dyn_cast(record); if (CXXDecl && CXXDecl->isLambda()) CollectRecordLambdaFields(CXXDecl, elements, RecordTy); else { const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record); // Debug info for nested records is included in the member list only for // CodeView. bool IncludeNestedRecords = CGM.getCodeGenOpts().EmitCodeView; // Field number for non-static fields. unsigned fieldNo = 0; // Static and non-static members should appear in the same order as // the corresponding declarations in the source program. for (const auto *I : record->decls()) if (const auto *V = dyn_cast(I)) { if (V->hasAttr()) continue; // Reuse the existing static member declaration if one exists auto MI = StaticDataMemberCache.find(V->getCanonicalDecl()); if (MI != StaticDataMemberCache.end()) { assert(MI->second && "Static data member declaration should still exist"); elements.push_back(MI->second); } else { auto Field = CreateRecordStaticField(V, RecordTy, record); elements.push_back(Field); } } else if (const auto *field = dyn_cast(I)) { CollectRecordNormalField(field, layout.getFieldOffset(fieldNo), tunit, elements, RecordTy, record); // Bump field number for next field. ++fieldNo; } else if (const auto *nestedRec = dyn_cast(I)) if (IncludeNestedRecords && !nestedRec->isImplicit() && nestedRec->getDeclContext() == record) CollectRecordNestedRecord(nestedRec, elements); } } llvm::DISubroutineType * CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile *Unit) { const FunctionProtoType *Func = Method->getType()->getAs(); if (Method->isStatic()) return cast_or_null( getOrCreateType(QualType(Func, 0), Unit)); return getOrCreateInstanceMethodType(Method->getThisType(CGM.getContext()), Func, Unit); } llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType( QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile *Unit) { // Add "this" pointer. llvm::DITypeRefArray Args( cast(getOrCreateType(QualType(Func, 0), Unit)) ->getTypeArray()); assert(Args.size() && "Invalid number of arguments!"); SmallVector Elts; // First element is always return type. For 'void' functions it is NULL. Elts.push_back(Args[0]); // "this" pointer is always first argument. const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl(); if (isa(RD)) { // Create pointer type directly in this case. const PointerType *ThisPtrTy = cast(ThisPtr); QualType PointeeTy = ThisPtrTy->getPointeeType(); unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); uint64_t Size = CGM.getTarget().getPointerWidth(AS); auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext()); llvm::DIType *PointeeType = getOrCreateType(PointeeTy, Unit); llvm::DIType *ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align); TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); // TODO: This and the artificial type below are misleading, the // types aren't artificial the argument is, but the current // metadata doesn't represent that. ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); Elts.push_back(ThisPtrType); } else { llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit); TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); Elts.push_back(ThisPtrType); } // Copy rest of the arguments. for (unsigned i = 1, e = Args.size(); i != e; ++i) Elts.push_back(Args[i]); llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts); llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (Func->getExtProtoInfo().RefQualifier == RQ_LValue) Flags |= llvm::DINode::FlagLValueReference; if (Func->getExtProtoInfo().RefQualifier == RQ_RValue) Flags |= llvm::DINode::FlagRValueReference; return DBuilder.createSubroutineType(EltTypeArray, Flags, getDwarfCC(Func->getCallConv())); } /// isFunctionLocalClass - Return true if CXXRecordDecl is defined /// inside a function. static bool isFunctionLocalClass(const CXXRecordDecl *RD) { if (const auto *NRD = dyn_cast(RD->getDeclContext())) return isFunctionLocalClass(NRD); if (isa(RD->getDeclContext())) return true; return false; } llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) { bool IsCtorOrDtor = isa(Method) || isa(Method); StringRef MethodName = getFunctionName(Method); llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit); // Since a single ctor/dtor corresponds to multiple functions, it doesn't // make sense to give a single ctor/dtor a linkage name. StringRef MethodLinkageName; // FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional // property to use here. It may've been intended to model "is non-external // type" but misses cases of non-function-local but non-external classes such // as those in anonymous namespaces as well as the reverse - external types // that are function local, such as those in (non-local) inline functions. if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent())) MethodLinkageName = CGM.getMangledName(Method); // Get the location for the method. llvm::DIFile *MethodDefUnit = nullptr; unsigned MethodLine = 0; if (!Method->isImplicit()) { MethodDefUnit = getOrCreateFile(Method->getLocation()); MethodLine = getLineNumber(Method->getLocation()); } // Collect virtual method info. llvm::DIType *ContainingType = nullptr; unsigned Virtuality = 0; unsigned VIndex = 0; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; int ThisAdjustment = 0; if (Method->isVirtual()) { if (Method->isPure()) Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual; else Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual; if (CGM.getTarget().getCXXABI().isItaniumFamily()) { // It doesn't make sense to give a virtual destructor a vtable index, // since a single destructor has two entries in the vtable. if (!isa(Method)) VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method); } else { // Emit MS ABI vftable information. There is only one entry for the // deleting dtor. const auto *DD = dyn_cast(Method); GlobalDecl GD = DD ? GlobalDecl(DD, Dtor_Deleting) : GlobalDecl(Method); MicrosoftVTableContext::MethodVFTableLocation ML = CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD); VIndex = ML.Index; // CodeView only records the vftable offset in the class that introduces // the virtual method. This is possible because, unlike Itanium, the MS // C++ ABI does not include all virtual methods from non-primary bases in // the vtable for the most derived class. For example, if C inherits from // A and B, C's primary vftable will not include B's virtual methods. if (Method->begin_overridden_methods() == Method->end_overridden_methods()) Flags |= llvm::DINode::FlagIntroducedVirtual; // The 'this' adjustment accounts for both the virtual and non-virtual // portions of the adjustment. Presumably the debugger only uses it when // it knows the dynamic type of an object. ThisAdjustment = CGM.getCXXABI() .getVirtualFunctionPrologueThisAdjustment(GD) .getQuantity(); } ContainingType = RecordTy; } if (Method->isImplicit()) Flags |= llvm::DINode::FlagArtificial; Flags |= getAccessFlag(Method->getAccess(), Method->getParent()); if (const auto *CXXC = dyn_cast(Method)) { if (CXXC->isExplicit()) Flags |= llvm::DINode::FlagExplicit; } else if (const auto *CXXC = dyn_cast(Method)) { if (CXXC->isExplicit()) Flags |= llvm::DINode::FlagExplicit; } if (Method->hasPrototype()) Flags |= llvm::DINode::FlagPrototyped; if (Method->getRefQualifier() == RQ_LValue) Flags |= llvm::DINode::FlagLValueReference; if (Method->getRefQualifier() == RQ_RValue) Flags |= llvm::DINode::FlagRValueReference; llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit); llvm::DISubprogram *SP = DBuilder.createMethod( RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine, MethodTy, /*isLocalToUnit=*/false, /*isDefinition=*/false, Virtuality, VIndex, ThisAdjustment, ContainingType, Flags, CGM.getLangOpts().Optimize, TParamsArray.get()); SPCache[Method->getCanonicalDecl()].reset(SP); return SP; } void CGDebugInfo::CollectCXXMemberFunctions( const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl &EltTys, llvm::DIType *RecordTy) { // Since we want more than just the individual member decls if we // have templated functions iterate over every declaration to gather // the functions. for (const auto *I : RD->decls()) { const auto *Method = dyn_cast(I); // If the member is implicit, don't add it to the member list. This avoids // the member being added to type units by LLVM, while still allowing it // to be emitted into the type declaration/reference inside the compile // unit. // Ditto 'nodebug' methods, for consistency with CodeGenFunction.cpp. // FIXME: Handle Using(Shadow?)Decls here to create // DW_TAG_imported_declarations inside the class for base decls brought into // derived classes. GDB doesn't seem to notice/leverage these when I tried // it, so I'm not rushing to fix this. (GCC seems to produce them, if // referenced) if (!Method || Method->isImplicit() || Method->hasAttr()) continue; if (Method->getType()->getAs()->getContainedAutoType()) continue; // Reuse the existing member function declaration if it exists. // It may be associated with the declaration of the type & should be // reused as we're building the definition. // // This situation can arise in the vtable-based debug info reduction where // implicit members are emitted in a non-vtable TU. auto MI = SPCache.find(Method->getCanonicalDecl()); EltTys.push_back(MI == SPCache.end() ? CreateCXXMemberFunction(Method, Unit, RecordTy) : static_cast(MI->second)); } } void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl &EltTys, llvm::DIType *RecordTy) { llvm::DenseSet> SeenTypes; CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->bases(), SeenTypes, llvm::DINode::FlagZero); // If we are generating CodeView debug info, we also need to emit records for // indirect virtual base classes. if (CGM.getCodeGenOpts().EmitCodeView) { CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->vbases(), SeenTypes, llvm::DINode::FlagIndirectVirtualBase); } } void CGDebugInfo::CollectCXXBasesAux( const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl &EltTys, llvm::DIType *RecordTy, const CXXRecordDecl::base_class_const_range &Bases, llvm::DenseSet> &SeenTypes, llvm::DINode::DIFlags StartingFlags) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); for (const auto &BI : Bases) { const auto *Base = cast(BI.getType()->getAs()->getDecl()); if (!SeenTypes.insert(Base).second) continue; auto *BaseTy = getOrCreateType(BI.getType(), Unit); llvm::DINode::DIFlags BFlags = StartingFlags; uint64_t BaseOffset; if (BI.isVirtual()) { if (CGM.getTarget().getCXXABI().isItaniumFamily()) { // virtual base offset offset is -ve. The code generator emits dwarf // expression where it expects +ve number. BaseOffset = 0 - CGM.getItaniumVTableContext() .getVirtualBaseOffsetOffset(RD, Base) .getQuantity(); } else { // In the MS ABI, store the vbtable offset, which is analogous to the // vbase offset offset in Itanium. BaseOffset = 4 * CGM.getMicrosoftVTableContext().getVBTableIndex(RD, Base); } BFlags |= llvm::DINode::FlagVirtual; } else BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base)); // FIXME: Inconsistent units for BaseOffset. It is in bytes when // BI->isVirtual() and bits when not. BFlags |= getAccessFlag(BI.getAccessSpecifier(), RD); llvm::DIType *DTy = DBuilder.createInheritance(RecordTy, BaseTy, BaseOffset, BFlags); EltTys.push_back(DTy); } } llvm::DINodeArray CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, ArrayRef TAList, llvm::DIFile *Unit) { SmallVector TemplateParams; for (unsigned i = 0, e = TAList.size(); i != e; ++i) { const TemplateArgument &TA = TAList[i]; StringRef Name; if (TPList) Name = TPList->getParam(i)->getName(); switch (TA.getKind()) { case TemplateArgument::Type: { llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit); TemplateParams.push_back( DBuilder.createTemplateTypeParameter(TheCU, Name, TTy)); } break; case TemplateArgument::Integral: { llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit); TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral()))); } break; case TemplateArgument::Declaration: { const ValueDecl *D = TA.getAsDecl(); QualType T = TA.getParamTypeForDecl().getDesugaredType(CGM.getContext()); llvm::DIType *TTy = getOrCreateType(T, Unit); llvm::Constant *V = nullptr; const CXXMethodDecl *MD; // Variable pointer template parameters have a value that is the address // of the variable. if (const auto *VD = dyn_cast(D)) V = CGM.GetAddrOfGlobalVar(VD); // Member function pointers have special support for building them, though // this is currently unsupported in LLVM CodeGen. else if ((MD = dyn_cast(D)) && MD->isInstance()) V = CGM.getCXXABI().EmitMemberFunctionPointer(MD); else if (const auto *FD = dyn_cast(D)) V = CGM.GetAddrOfFunction(FD); // Member data pointers have special handling too to compute the fixed // offset within the object. else if (const auto *MPT = dyn_cast(T.getTypePtr())) { // These five lines (& possibly the above member function pointer // handling) might be able to be refactored to use similar code in // CodeGenModule::getMemberPointerConstant uint64_t fieldOffset = CGM.getContext().getFieldOffset(D); CharUnits chars = CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset); V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars); } TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, cast_or_null(V->stripPointerCasts()))); } break; case TemplateArgument::NullPtr: { QualType T = TA.getNullPtrType(); llvm::DIType *TTy = getOrCreateType(T, Unit); llvm::Constant *V = nullptr; // Special case member data pointer null values since they're actually -1 // instead of zero. if (const auto *MPT = dyn_cast(T.getTypePtr())) // But treat member function pointers as simple zero integers because // it's easier than having a special case in LLVM's CodeGen. If LLVM // CodeGen grows handling for values of non-null member function // pointers then perhaps we could remove this special case and rely on // EmitNullMemberPointer for member function pointers. if (MPT->isMemberDataPointer()) V = CGM.getCXXABI().EmitNullMemberPointer(MPT); if (!V) V = llvm::ConstantInt::get(CGM.Int8Ty, 0); TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, V)); } break; case TemplateArgument::Template: TemplateParams.push_back(DBuilder.createTemplateTemplateParameter( TheCU, Name, nullptr, TA.getAsTemplate().getAsTemplateDecl()->getQualifiedNameAsString())); break; case TemplateArgument::Pack: TemplateParams.push_back(DBuilder.createTemplateParameterPack( TheCU, Name, nullptr, CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit))); break; case TemplateArgument::Expression: { const Expr *E = TA.getAsExpr(); QualType T = E->getType(); if (E->isGLValue()) T = CGM.getContext().getLValueReferenceType(T); llvm::Constant *V = CGM.EmitConstantExpr(E, T); assert(V && "Expression in template argument isn't constant"); llvm::DIType *TTy = getOrCreateType(T, Unit); TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, V->stripPointerCasts())); } break; // And the following should never occur: case TemplateArgument::TemplateExpansion: case TemplateArgument::Null: llvm_unreachable( "These argument types shouldn't exist in concrete types"); } } return DBuilder.getOrCreateArray(TemplateParams); } llvm::DINodeArray CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile *Unit) { if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization) { const TemplateParameterList *TList = FD->getTemplateSpecializationInfo() ->getTemplate() ->getTemplateParameters(); return CollectTemplateParams( TList, FD->getTemplateSpecializationArgs()->asArray(), Unit); } return llvm::DINodeArray(); } llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams( const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) { // Always get the full list of parameters, not just the ones from // the specialization. TemplateParameterList *TPList = TSpecial->getSpecializedTemplate()->getTemplateParameters(); const TemplateArgumentList &TAList = TSpecial->getTemplateArgs(); return CollectTemplateParams(TPList, TAList.asArray(), Unit); } llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { if (VTablePtrType) return VTablePtrType; ASTContext &Context = CGM.getContext(); /* Function type */ llvm::Metadata *STy = getOrCreateType(Context.IntTy, Unit); llvm::DITypeRefArray SElements = DBuilder.getOrCreateTypeArray(STy); llvm::DIType *SubTy = DBuilder.createSubroutineType(SElements); unsigned Size = Context.getTypeSize(Context.VoidPtrTy); unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace(); Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace); llvm::DIType *vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0, DWARFAddressSpace, "__vtbl_ptr_type"); VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size); return VTablePtrType; } StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // Copy the gdb compatible name on the side and use its reference. return internString("_vptr$", RD->getNameAsString()); } void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, SmallVectorImpl &EltTys, llvm::DICompositeType *RecordTy) { // If this class is not dynamic then there is not any vtable info to collect. if (!RD->isDynamicClass()) return; // Don't emit any vtable shape or vptr info if this class doesn't have an // extendable vfptr. This can happen if the class doesn't have virtual // methods, or in the MS ABI if those virtual methods only come from virtually // inherited bases. const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); if (!RL.hasExtendableVFPtr()) return; // CodeView needs to know how large the vtable of every dynamic class is, so // emit a special named pointer type into the element list. The vptr type // points to this type as well. llvm::DIType *VPtrTy = nullptr; bool NeedVTableShape = CGM.getCodeGenOpts().EmitCodeView && CGM.getTarget().getCXXABI().isMicrosoft(); if (NeedVTableShape) { uint64_t PtrWidth = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); const VTableLayout &VFTLayout = CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero()); unsigned VSlotCount = VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData; unsigned VTableWidth = PtrWidth * VSlotCount; unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace(); Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace); // Create a very wide void* type and insert it directly in the element list. llvm::DIType *VTableType = DBuilder.createPointerType(nullptr, VTableWidth, 0, DWARFAddressSpace, "__vtbl_ptr_type"); EltTys.push_back(VTableType); // The vptr is a pointer to this special vtable type. VPtrTy = DBuilder.createPointerType(VTableType, PtrWidth); } // If there is a primary base then the artificial vptr member lives there. if (RL.getPrimaryBase()) return; if (!VPtrTy) VPtrTy = getOrCreateVTablePtrType(Unit); unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); llvm::DIType *VPtrMember = DBuilder.createMemberType( Unit, getVTableName(RD), Unit, 0, Size, 0, 0, llvm::DINode::FlagArtificial, VPtrTy); EltTys.push_back(VPtrMember); } llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy, SourceLocation Loc) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); llvm::DIType *T = getOrCreateType(RTy, getOrCreateFile(Loc)); return T; } llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D, SourceLocation Loc) { return getOrCreateStandaloneType(D, Loc); } llvm::DIType *CGDebugInfo::getOrCreateStandaloneType(QualType D, SourceLocation Loc) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); assert(!D.isNull() && "null type"); llvm::DIType *T = getOrCreateType(D, getOrCreateFile(Loc)); assert(T && "could not create debug info for type"); RetainedTypes.push_back(D.getAsOpaquePtr()); return T; } void CGDebugInfo::completeType(const EnumDecl *ED) { if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; QualType Ty = CGM.getContext().getEnumType(ED); void *TyPtr = Ty.getAsOpaquePtr(); auto I = TypeCache.find(TyPtr); if (I == TypeCache.end() || !cast(I->second)->isForwardDecl()) return; llvm::DIType *Res = CreateTypeDefinition(Ty->castAs()); assert(!Res->isForwardDecl()); TypeCache[TyPtr].reset(Res); } void CGDebugInfo::completeType(const RecordDecl *RD) { if (DebugKind > codegenoptions::LimitedDebugInfo || !CGM.getLangOpts().CPlusPlus) completeRequiredType(RD); } /// Return true if the class or any of its methods are marked dllimport. static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) { if (RD->hasAttr()) return true; for (const CXXMethodDecl *MD : RD->methods()) if (MD->hasAttr()) return true; return false; } void CGDebugInfo::completeClassData(const RecordDecl *RD) { if (auto *CXXRD = dyn_cast(RD)) if (CXXRD->isDynamicClass() && CGM.getVTableLinkage(CXXRD) == llvm::GlobalValue::AvailableExternallyLinkage && !isClassOrMethodDLLImport(CXXRD)) return; completeClass(RD); } void CGDebugInfo::completeClass(const RecordDecl *RD) { if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; QualType Ty = CGM.getContext().getRecordType(RD); void *TyPtr = Ty.getAsOpaquePtr(); auto I = TypeCache.find(TyPtr); if (I != TypeCache.end() && !cast(I->second)->isForwardDecl()) return; llvm::DIType *Res = CreateTypeDefinition(Ty->castAs()); assert(!Res->isForwardDecl()); TypeCache[TyPtr].reset(Res); } static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I, CXXRecordDecl::method_iterator End) { for (CXXMethodDecl *MD : llvm::make_range(I, End)) if (FunctionDecl *Tmpl = MD->getInstantiatedFromMemberFunction()) if (!Tmpl->isImplicit() && Tmpl->isThisDeclarationADefinition() && !MD->getMemberSpecializationInfo()->isExplicitSpecialization()) return true; return false; } /// Does a type definition exist in an imported clang module? static bool isDefinedInClangModule(const RecordDecl *RD) { // Only definitions that where imported from an AST file come from a module. if (!RD || !RD->isFromASTFile()) return false; // Anonymous entities cannot be addressed. Treat them as not from module. if (!RD->isExternallyVisible() && RD->getName().empty()) return false; if (auto *CXXDecl = dyn_cast(RD)) { if (!CXXDecl->isCompleteDefinition()) return false; auto TemplateKind = CXXDecl->getTemplateSpecializationKind(); if (TemplateKind != TSK_Undeclared) { // This is a template, check the origin of the first member. if (CXXDecl->field_begin() == CXXDecl->field_end()) return TemplateKind == TSK_ExplicitInstantiationDeclaration; if (!CXXDecl->field_begin()->isFromASTFile()) return false; } } return true; } static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind, bool DebugTypeExtRefs, const RecordDecl *RD, const LangOptions &LangOpts) { if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition())) return true; if (auto *ES = RD->getASTContext().getExternalSource()) if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always) return true; if (DebugKind > codegenoptions::LimitedDebugInfo) return false; if (!LangOpts.CPlusPlus) return false; if (!RD->isCompleteDefinitionRequired()) return true; const auto *CXXDecl = dyn_cast(RD); if (!CXXDecl) return false; // Only emit complete debug info for a dynamic class when its vtable is // emitted. However, Microsoft debuggers don't resolve type information // across DLL boundaries, so skip this optimization if the class or any of its // methods are marked dllimport. This isn't a complete solution, since objects // without any dllimport methods can be used in one DLL and constructed in // another, but it is the current behavior of LimitedDebugInfo. if (CXXDecl->hasDefinition() && CXXDecl->isDynamicClass() && !isClassOrMethodDLLImport(CXXDecl)) return true; TemplateSpecializationKind Spec = TSK_Undeclared; if (const auto *SD = dyn_cast(RD)) Spec = SD->getSpecializationKind(); if (Spec == TSK_ExplicitInstantiationDeclaration && hasExplicitMemberDefinition(CXXDecl->method_begin(), CXXDecl->method_end())) return true; return false; } void CGDebugInfo::completeRequiredType(const RecordDecl *RD) { if (shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD, CGM.getLangOpts())) return; QualType Ty = CGM.getContext().getRecordType(RD); llvm::DIType *T = getTypeOrNull(Ty); if (T && T->isForwardDecl()) completeClassData(RD); } llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); llvm::DIType *T = cast_or_null(getTypeOrNull(QualType(Ty, 0))); if (T || shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD, CGM.getLangOpts())) { if (!T) T = getOrCreateRecordFwdDecl(Ty, getDeclContextDescriptor(RD)); return T; } return CreateTypeDefinition(Ty); } llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); // Get overall information about the record type for the debug info. llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation()); // Records and classes and unions can all be recursive. To handle them, we // first generate a debug descriptor for the struct as a forward declaration. // Then (if it is a definition) we go through and get debug info for all of // its members. Finally, we create a descriptor for the complete type (which // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. llvm::DICompositeType *FwdDecl = getOrCreateLimitedType(Ty, DefUnit); const RecordDecl *D = RD->getDefinition(); if (!D || !D->isCompleteDefinition()) return FwdDecl; if (const auto *CXXDecl = dyn_cast(RD)) CollectContainingType(CXXDecl, FwdDecl); // Push the struct on region stack. LexicalBlockStack.emplace_back(&*FwdDecl); RegionMap[Ty->getDecl()].reset(FwdDecl); // Convert all the elements. SmallVector EltTys; // what about nested types? // Note: The split of CXXDecl information here is intentional, the // gdb tests will depend on a certain ordering at printout. The debug // information offsets are still correct if we merge them all together // though. const auto *CXXDecl = dyn_cast(RD); if (CXXDecl) { CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl); CollectVTableInfo(CXXDecl, DefUnit, EltTys, FwdDecl); } // Collect data fields (including static variables and any initializers). CollectRecordFields(RD, DefUnit, EltTys, FwdDecl); if (CXXDecl) CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl); LexicalBlockStack.pop_back(); RegionMap.erase(Ty->getDecl()); llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); DBuilder.replaceArrays(FwdDecl, Elements); if (FwdDecl->isTemporary()) FwdDecl = llvm::MDNode::replaceWithPermanent(llvm::TempDICompositeType(FwdDecl)); RegionMap[Ty->getDecl()].reset(FwdDecl); return FwdDecl; } llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty, llvm::DIFile *Unit) { // Ignore protocols. return getOrCreateType(Ty->getBaseType(), Unit); } llvm::DIType *CGDebugInfo::CreateType(const ObjCTypeParamType *Ty, llvm::DIFile *Unit) { // Ignore protocols. SourceLocation Loc = Ty->getDecl()->getLocation(); // Use Typedefs to represent ObjCTypeParamType. return DBuilder.createTypedef( getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit), Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc), getDeclContextDescriptor(Ty->getDecl())); } /// \return true if Getter has the default name for the property PD. static bool hasDefaultGetterName(const ObjCPropertyDecl *PD, const ObjCMethodDecl *Getter) { assert(PD); if (!Getter) return true; assert(Getter->getDeclName().isObjCZeroArgSelector()); return PD->getName() == Getter->getDeclName().getObjCSelector().getNameForSlot(0); } /// \return true if Setter has the default name for the property PD. static bool hasDefaultSetterName(const ObjCPropertyDecl *PD, const ObjCMethodDecl *Setter) { assert(PD); if (!Setter) return true; assert(Setter->getDeclName().isObjCOneArgSelector()); return SelectorTable::constructSetterName(PD->getName()) == Setter->getDeclName().getObjCSelector().getNameForSlot(0); } llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIFile *Unit) { ObjCInterfaceDecl *ID = Ty->getDecl(); if (!ID) return nullptr; // Return a forward declaration if this type was imported from a clang module, // and this is not the compile unit with the implementation of the type (which // may contain hidden ivars). if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition() && !ID->getImplementation()) return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, ID->getName(), getDeclContextDescriptor(ID), Unit, 0); // Get overall information about the record type for the debug info. llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation()); unsigned Line = getLineNumber(ID->getLocation()); auto RuntimeLang = static_cast(TheCU->getSourceLanguage()); // If this is just a forward declaration return a special forward-declaration // debug type since we won't be able to lay out the entire type. ObjCInterfaceDecl *Def = ID->getDefinition(); if (!Def || !Def->getImplementation()) { llvm::DIScope *Mod = getParentModuleOrNull(ID); llvm::DIType *FwdDecl = DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_structure_type, ID->getName(), Mod ? Mod : TheCU, DefUnit, Line, RuntimeLang); ObjCInterfaceCache.push_back(ObjCInterfaceCacheEntry(Ty, FwdDecl, Unit)); return FwdDecl; } return CreateTypeDefinition(Ty, Unit); } llvm::DIModule * CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, bool CreateSkeletonCU) { // Use the Module pointer as the key into the cache. This is a // nullptr if the "Module" is a PCH, which is safe because we don't // support chained PCH debug info, so there can only be a single PCH. const Module *M = Mod.getModuleOrNull(); auto ModRef = ModuleCache.find(M); if (ModRef != ModuleCache.end()) return cast(ModRef->second); // Macro definitions that were defined with "-D" on the command line. SmallString<128> ConfigMacros; { llvm::raw_svector_ostream OS(ConfigMacros); const auto &PPOpts = CGM.getPreprocessorOpts(); unsigned I = 0; // Translate the macro definitions back into a commmand line. for (auto &M : PPOpts.Macros) { if (++I > 1) OS << " "; const std::string &Macro = M.first; bool Undef = M.second; OS << "\"-" << (Undef ? 'U' : 'D'); for (char c : Macro) switch (c) { case '\\' : OS << "\\\\"; break; case '"' : OS << "\\\""; break; default: OS << c; } OS << '\"'; } } bool IsRootModule = M ? !M->Parent : true; if (CreateSkeletonCU && IsRootModule) { // PCH files don't have a signature field in the control block, // but LLVM detects skeleton CUs by looking for a non-zero DWO id. // We use the lower 64 bits for debug info. uint64_t Signature = Mod.getSignature() ? (uint64_t)Mod.getSignature()[1] << 32 | Mod.getSignature()[0] : ~1ULL; llvm::DIBuilder DIB(CGM.getModule()); DIB.createCompileUnit(TheCU->getSourceLanguage(), DIB.createFile(Mod.getModuleName(), Mod.getPath()), TheCU->getProducer(), true, StringRef(), 0, Mod.getASTFile(), llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } llvm::DIModule *Parent = IsRootModule ? nullptr : getOrCreateModuleRef( ExternalASTSource::ASTSourceDescriptor(*M->Parent), CreateSkeletonCU); llvm::DIModule *DIMod = DBuilder.createModule(Parent, Mod.getModuleName(), ConfigMacros, Mod.getPath(), CGM.getHeaderSearchOpts().Sysroot); ModuleCache[M].reset(DIMod); return DIMod; } llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile *Unit) { ObjCInterfaceDecl *ID = Ty->getDecl(); llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation()); unsigned Line = getLineNumber(ID->getLocation()); unsigned RuntimeLang = TheCU->getSourceLanguage(); // Bit size, align and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(Ty); auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (ID->getImplementation()) Flags |= llvm::DINode::FlagObjcClassComplete; llvm::DIScope *Mod = getParentModuleOrNull(ID); llvm::DICompositeType *RealDecl = DBuilder.createStructType( Mod ? Mod : Unit, ID->getName(), DefUnit, Line, Size, Align, Flags, nullptr, llvm::DINodeArray(), RuntimeLang); QualType QTy(Ty, 0); TypeCache[QTy.getAsOpaquePtr()].reset(RealDecl); // Push the struct on region stack. LexicalBlockStack.emplace_back(RealDecl); RegionMap[Ty->getDecl()].reset(RealDecl); // Convert all the elements. SmallVector EltTys; ObjCInterfaceDecl *SClass = ID->getSuperClass(); if (SClass) { llvm::DIType *SClassTy = getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit); if (!SClassTy) return nullptr; llvm::DIType *InhTag = DBuilder.createInheritance(RealDecl, SClassTy, 0, llvm::DINode::FlagZero); EltTys.push_back(InhTag); } // Create entries for all of the properties. auto AddProperty = [&](const ObjCPropertyDecl *PD) { SourceLocation Loc = PD->getLocation(); llvm::DIFile *PUnit = getOrCreateFile(Loc); unsigned PLine = getLineNumber(Loc); ObjCMethodDecl *Getter = PD->getGetterMethodDecl(); ObjCMethodDecl *Setter = PD->getSetterMethodDecl(); llvm::MDNode *PropertyNode = DBuilder.createObjCProperty( PD->getName(), PUnit, PLine, hasDefaultGetterName(PD, Getter) ? "" : getSelectorName(PD->getGetterName()), hasDefaultSetterName(PD, Setter) ? "" : getSelectorName(PD->getSetterName()), PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit)); EltTys.push_back(PropertyNode); }; { llvm::SmallPtrSet PropertySet; for (const ObjCCategoryDecl *ClassExt : ID->known_extensions()) for (auto *PD : ClassExt->properties()) { PropertySet.insert(PD->getIdentifier()); AddProperty(PD); } for (const auto *PD : ID->properties()) { // Don't emit duplicate metadata for properties that were already in a // class extension. if (!PropertySet.insert(PD->getIdentifier()).second) continue; AddProperty(PD); } } const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID); unsigned FieldNo = 0; for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field; Field = Field->getNextIvar(), ++FieldNo) { llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit); if (!FieldTy) return nullptr; StringRef FieldName = Field->getName(); // Ignore unnamed fields. if (FieldName.empty()) continue; // Get the location for the field. llvm::DIFile *FieldDefUnit = getOrCreateFile(Field->getLocation()); unsigned FieldLine = getLineNumber(Field->getLocation()); QualType FType = Field->getType(); uint64_t FieldSize = 0; uint32_t FieldAlign = 0; if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. FieldSize = Field->isBitField() ? Field->getBitWidthValue(CGM.getContext()) : CGM.getContext().getTypeSize(FType); FieldAlign = getTypeAlignIfRequired(FType, CGM.getContext()); } uint64_t FieldOffset; if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { // We don't know the runtime offset of an ivar if we're using the // non-fragile ABI. For bitfields, use the bit offset into the first // byte of storage of the bitfield. For other fields, use zero. if (Field->isBitField()) { FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset(CGM, ID, Field); FieldOffset %= CGM.getContext().getCharWidth(); } else { FieldOffset = 0; } } else { FieldOffset = RL.getFieldOffset(FieldNo); } llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (Field->getAccessControl() == ObjCIvarDecl::Protected) Flags = llvm::DINode::FlagProtected; else if (Field->getAccessControl() == ObjCIvarDecl::Private) Flags = llvm::DINode::FlagPrivate; else if (Field->getAccessControl() == ObjCIvarDecl::Public) Flags = llvm::DINode::FlagPublic; llvm::MDNode *PropertyNode = nullptr; if (ObjCImplementationDecl *ImpD = ID->getImplementation()) { if (ObjCPropertyImplDecl *PImpD = ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) { if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) { SourceLocation Loc = PD->getLocation(); llvm::DIFile *PUnit = getOrCreateFile(Loc); unsigned PLine = getLineNumber(Loc); ObjCMethodDecl *Getter = PD->getGetterMethodDecl(); ObjCMethodDecl *Setter = PD->getSetterMethodDecl(); PropertyNode = DBuilder.createObjCProperty( PD->getName(), PUnit, PLine, hasDefaultGetterName(PD, Getter) ? "" : getSelectorName( PD->getGetterName()), hasDefaultSetterName(PD, Setter) ? "" : getSelectorName( PD->getSetterName()), PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit)); } } } FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, FieldLine, FieldSize, FieldAlign, FieldOffset, Flags, FieldTy, PropertyNode); EltTys.push_back(FieldTy); } llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); DBuilder.replaceArrays(RealDecl, Elements); LexicalBlockStack.pop_back(); return RealDecl; } llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile *Unit) { llvm::DIType *ElementTy = getOrCreateType(Ty->getElementType(), Unit); int64_t Count = Ty->getNumElements(); if (Count == 0) // If number of elements are not known then this is an unbounded array. // Use Count == -1 to express such arrays. Count = -1; llvm::Metadata *Subscript = DBuilder.getOrCreateSubrange(0, Count); llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); uint64_t Size = CGM.getContext().getTypeSize(Ty); auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray); } llvm::DIType *CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIFile *Unit) { uint64_t Size; uint32_t Align; // FIXME: make getTypeAlign() aware of VLAs and incomplete array types if (const auto *VAT = dyn_cast(Ty)) { Size = 0; Align = getTypeAlignIfRequired(CGM.getContext().getBaseElementType(VAT), CGM.getContext()); } else if (Ty->isIncompleteArrayType()) { Size = 0; if (Ty->getElementType()->isIncompleteType()) Align = 0; else Align = getTypeAlignIfRequired(Ty->getElementType(), CGM.getContext()); } else if (Ty->isIncompleteType()) { Size = 0; Align = 0; } else { // Size and align of the whole array, not the element type. Size = CGM.getContext().getTypeSize(Ty); Align = getTypeAlignIfRequired(Ty, CGM.getContext()); } // Add the dimensions of the array. FIXME: This loses CV qualifiers from // interior arrays, do we care? Why aren't nested arrays represented the // obvious/recursive way? SmallVector Subscripts; QualType EltTy(Ty, 0); while ((Ty = dyn_cast(EltTy))) { // If the number of elements is known, then count is that number. Otherwise, // it's -1. This allows us to represent a subrange with an array of 0 // elements, like this: // // struct foo { // int x[0]; // }; int64_t Count = -1; // Count == -1 is an unbounded array. if (const auto *CAT = dyn_cast(Ty)) Count = CAT->getSize().getZExtValue(); else if (const auto *VAT = dyn_cast(Ty)) { if (Expr *Size = VAT->getSizeExpr()) { llvm::APSInt V; if (Size->EvaluateAsInt(V, CGM.getContext())) Count = V.getExtValue(); } } // FIXME: Verify this is right for VLAs. Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count)); EltTy = Ty->getElementType(); } llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts); return DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit), SubscriptArray); } llvm::DIType *CGDebugInfo::CreateType(const LValueReferenceType *Ty, llvm::DIFile *Unit) { return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type, Ty, Ty->getPointeeType(), Unit); } llvm::DIType *CGDebugInfo::CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit) { return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type, Ty, Ty->getPointeeType(), Unit); } llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty, llvm::DIFile *U) { llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; uint64_t Size = 0; if (!Ty->isIncompleteType()) { Size = CGM.getContext().getTypeSize(Ty); // Set the MS inheritance model. There is no flag for the unspecified model. if (CGM.getTarget().getCXXABI().isMicrosoft()) { switch (Ty->getMostRecentCXXRecordDecl()->getMSInheritanceModel()) { case MSInheritanceAttr::Keyword_single_inheritance: Flags |= llvm::DINode::FlagSingleInheritance; break; case MSInheritanceAttr::Keyword_multiple_inheritance: Flags |= llvm::DINode::FlagMultipleInheritance; break; case MSInheritanceAttr::Keyword_virtual_inheritance: Flags |= llvm::DINode::FlagVirtualInheritance; break; case MSInheritanceAttr::Keyword_unspecified_inheritance: break; } } } llvm::DIType *ClassType = getOrCreateType(QualType(Ty->getClass(), 0), U); if (Ty->isMemberDataPointerType()) return DBuilder.createMemberPointerType( getOrCreateType(Ty->getPointeeType(), U), ClassType, Size, /*Align=*/0, Flags); const FunctionProtoType *FPT = Ty->getPointeeType()->getAs(); return DBuilder.createMemberPointerType( getOrCreateInstanceMethodType(CGM.getContext().getPointerType(QualType( Ty->getClass(), FPT->getTypeQuals())), FPT, U), ClassType, Size, /*Align=*/0, Flags); } llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) { auto *FromTy = getOrCreateType(Ty->getValueType(), U); return DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_atomic_type, FromTy); } llvm::DIType* CGDebugInfo::CreateType(const PipeType *Ty, llvm::DIFile *U) { return getOrCreateType(Ty->getElementType(), U); } llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); uint64_t Size = 0; uint32_t Align = 0; if (!ED->getTypeForDecl()->isIncompleteType()) { Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); Align = getDeclAlignIfRequired(ED, CGM.getContext()); } SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU); bool isImportedFromModule = DebugTypeExtRefs && ED->isFromASTFile() && ED->getDefinition(); // If this is just a forward declaration, construct an appropriately // marked node and just return it. if (isImportedFromModule || !ED->getDefinition()) { // Note that it is possible for enums to be created as part of // their own declcontext. In this case a FwdDecl will be created // twice. This doesn't cause a problem because both FwdDecls are // entered into the ReplaceMap: finalize() will replace the first // FwdDecl with the second and then replace the second with // complete type. llvm::DIScope *EDContext = getDeclContextDescriptor(ED); llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation()); llvm::TempDIScope TmpContext(DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_enumeration_type, "", TheCU, DefUnit, 0)); unsigned Line = getLineNumber(ED->getLocation()); StringRef EDName = ED->getName(); llvm::DIType *RetTy = DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_enumeration_type, EDName, EDContext, DefUnit, Line, 0, Size, Align, llvm::DINode::FlagFwdDecl, FullName); ReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(Ty), std::make_tuple(static_cast(RetTy))); return RetTy; } return CreateTypeDefinition(Ty); } llvm::DIType *CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); uint64_t Size = 0; uint32_t Align = 0; if (!ED->getTypeForDecl()->isIncompleteType()) { Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); Align = getDeclAlignIfRequired(ED, CGM.getContext()); } SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU); // Create elements for each enumerator. SmallVector Enumerators; ED = ED->getDefinition(); for (const auto *Enum : ED->enumerators()) { Enumerators.push_back(DBuilder.createEnumerator( Enum->getName(), Enum->getInitVal().getSExtValue())); } // Return a CompositeType for the enum itself. llvm::DINodeArray EltArray = DBuilder.getOrCreateArray(Enumerators); llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation()); unsigned Line = getLineNumber(ED->getLocation()); llvm::DIScope *EnumContext = getDeclContextDescriptor(ED); llvm::DIType *ClassTy = ED->isFixed() ? getOrCreateType(ED->getIntegerType(), DefUnit) : nullptr; return DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line, Size, Align, EltArray, ClassTy, FullName); } llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent, unsigned MType, SourceLocation LineLoc, StringRef Name, StringRef Value) { unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); return DBuilder.createMacro(Parent, Line, MType, Name, Value); } llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent, SourceLocation LineLoc, SourceLocation FileLoc) { llvm::DIFile *FName = getOrCreateFile(FileLoc); unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); return DBuilder.createTempMacroFile(Parent, Line, FName); } static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { Qualifiers Quals; do { Qualifiers InnerQuals = T.getLocalQualifiers(); // Qualifiers::operator+() doesn't like it if you add a Qualifier // that is already there. Quals += Qualifiers::removeCommonQualifiers(Quals, InnerQuals); Quals += InnerQuals; QualType LastT = T; switch (T->getTypeClass()) { default: return C.getQualifiedType(T.getTypePtr(), Quals); case Type::TemplateSpecialization: { const auto *Spec = cast(T); if (Spec->isTypeAlias()) return C.getQualifiedType(T.getTypePtr(), Quals); T = Spec->desugar(); break; } case Type::TypeOfExpr: T = cast(T)->getUnderlyingExpr()->getType(); break; case Type::TypeOf: T = cast(T)->getUnderlyingType(); break; case Type::Decltype: T = cast(T)->getUnderlyingType(); break; case Type::UnaryTransform: T = cast(T)->getUnderlyingType(); break; case Type::Attributed: T = cast(T)->getEquivalentType(); break; case Type::Elaborated: T = cast(T)->getNamedType(); break; case Type::Paren: T = cast(T)->getInnerType(); break; case Type::SubstTemplateTypeParm: T = cast(T)->getReplacementType(); break; case Type::Auto: case Type::DeducedTemplateSpecialization: { QualType DT = cast(T)->getDeducedType(); assert(!DT.isNull() && "Undeduced types shouldn't reach here."); T = DT; break; } case Type::Adjusted: case Type::Decayed: // Decayed and adjusted types use the adjusted type in LLVM and DWARF. T = cast(T)->getAdjustedType(); break; } assert(T != LastT && "Type unwrapping failed to unwrap!"); (void)LastT; } while (true); } llvm::DIType *CGDebugInfo::getTypeOrNull(QualType Ty) { // Unwrap the type as needed for debug information. Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext()); auto it = TypeCache.find(Ty.getAsOpaquePtr()); if (it != TypeCache.end()) { // Verify that the debug info still exists. if (llvm::Metadata *V = it->second) return cast(V); } return nullptr; } void CGDebugInfo::completeTemplateDefinition( const ClassTemplateSpecializationDecl &SD) { if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; completeUnusedClass(SD); } void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) { if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; completeClassData(&D); // In case this type has no member function definitions being emitted, ensure // it is retained RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr()); } llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { if (Ty.isNull()) return nullptr; // Unwrap the type as needed for debug information. Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext()); if (auto *T = getTypeOrNull(Ty)) return T; llvm::DIType *Res = CreateTypeNode(Ty, Unit); void* TyPtr = Ty.getAsOpaquePtr(); // And update the type cache. TypeCache[TyPtr].reset(Res); return Res; } llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) { // A forward declaration inside a module header does not belong to the module. if (isa(D) && !cast(D)->getDefinition()) return nullptr; if (DebugTypeExtRefs && D->isFromASTFile()) { // Record a reference to an imported clang module or precompiled header. auto *Reader = CGM.getContext().getExternalSource(); auto Idx = D->getOwningModuleID(); auto Info = Reader->getSourceDescriptor(Idx); if (Info) return getOrCreateModuleRef(*Info, /*SkeletonCU=*/true); } else if (ClangModuleMap) { // We are building a clang module or a precompiled header. // // TODO: When D is a CXXRecordDecl or a C++ Enum, the ODR applies // and it wouldn't be necessary to specify the parent scope // because the type is already unique by definition (it would look // like the output of -fno-standalone-debug). On the other hand, // the parent scope helps a consumer to quickly locate the object // file where the type's definition is located, so it might be // best to make this behavior a command line or debugger tuning // option. FullSourceLoc Loc(D->getLocation(), CGM.getContext().getSourceManager()); if (Module *M = ClangModuleMap->inferModuleFromLocation(Loc)) { // This is a (sub-)module. auto Info = ExternalASTSource::ASTSourceDescriptor(*M); return getOrCreateModuleRef(Info, /*SkeletonCU=*/false); } else { // This the precompiled header being built. return getOrCreateModuleRef(PCHDescriptor, /*SkeletonCU=*/false); } } return nullptr; } llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { // Handle qualifiers, which recursively handles what they refer to. if (Ty.hasLocalQualifiers()) return CreateQualifiedType(Ty, Unit); // Work out details of type. switch (Ty->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" llvm_unreachable("Dependent types cannot show up in debug information"); case Type::ExtVector: case Type::Vector: return CreateType(cast(Ty), Unit); case Type::ObjCObjectPointer: return CreateType(cast(Ty), Unit); case Type::ObjCObject: return CreateType(cast(Ty), Unit); case Type::ObjCTypeParam: return CreateType(cast(Ty), Unit); case Type::ObjCInterface: return CreateType(cast(Ty), Unit); case Type::Builtin: return CreateType(cast(Ty)); case Type::Complex: return CreateType(cast(Ty)); case Type::Pointer: return CreateType(cast(Ty), Unit); case Type::BlockPointer: return CreateType(cast(Ty), Unit); case Type::Typedef: return CreateType(cast(Ty), Unit); case Type::Record: return CreateType(cast(Ty)); case Type::Enum: return CreateEnumType(cast(Ty)); case Type::FunctionProto: case Type::FunctionNoProto: return CreateType(cast(Ty), Unit); case Type::ConstantArray: case Type::VariableArray: case Type::IncompleteArray: return CreateType(cast(Ty), Unit); case Type::LValueReference: return CreateType(cast(Ty), Unit); case Type::RValueReference: return CreateType(cast(Ty), Unit); case Type::MemberPointer: return CreateType(cast(Ty), Unit); case Type::Atomic: return CreateType(cast(Ty), Unit); case Type::Pipe: return CreateType(cast(Ty), Unit); case Type::TemplateSpecialization: return CreateType(cast(Ty), Unit); case Type::Auto: case Type::Attributed: case Type::Adjusted: case Type::Decayed: case Type::DeducedTemplateSpecialization: case Type::Elaborated: case Type::Paren: case Type::SubstTemplateTypeParm: case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: case Type::UnaryTransform: case Type::PackExpansion: break; } llvm_unreachable("type should have been unwrapped!"); } llvm::DICompositeType *CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *Unit) { QualType QTy(Ty, 0); auto *T = cast_or_null(getTypeOrNull(QTy)); // We may have cached a forward decl when we could have created // a non-forward decl. Go ahead and create a non-forward decl // now. if (T && !T->isForwardDecl()) return T; // Otherwise create the type. llvm::DICompositeType *Res = CreateLimitedType(Ty); // Propagate members from the declaration to the definition // CreateType(const RecordType*) will overwrite this with the members in the // correct order if the full type is needed. DBuilder.replaceArrays(Res, T ? T->getElements() : llvm::DINodeArray()); // And update the type cache. TypeCache[QTy.getAsOpaquePtr()].reset(Res); return Res; } // TODO: Currently used for context chains when limiting debug info. llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); // Get overall information about the record type for the debug info. llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation()); unsigned Line = getLineNumber(RD->getLocation()); StringRef RDName = getClassName(RD); llvm::DIScope *RDContext = getDeclContextDescriptor(RD); // If we ended up creating the type during the context chain construction, // just return that. auto *T = cast_or_null( getTypeOrNull(CGM.getContext().getRecordType(RD))); if (T && (!T->isForwardDecl() || !RD->getDefinition())) return T; // If this is just a forward or incomplete declaration, construct an // appropriately marked node and just return it. const RecordDecl *D = RD->getDefinition(); if (!D || !D->isCompleteDefinition()) return getOrCreateRecordFwdDecl(Ty, RDContext); uint64_t Size = CGM.getContext().getTypeSize(Ty); auto Align = getDeclAlignIfRequired(D, CGM.getContext()); SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU); llvm::DICompositeType *RealDecl = DBuilder.createReplaceableCompositeType( getTagForRecord(RD), RDName, RDContext, DefUnit, Line, 0, Size, Align, llvm::DINode::FlagZero, FullName); // Elements of composite types usually have back to the type, creating // uniquing cycles. Distinct nodes are more efficient. switch (RealDecl->getTag()) { default: llvm_unreachable("invalid composite type tag"); case llvm::dwarf::DW_TAG_array_type: case llvm::dwarf::DW_TAG_enumeration_type: // Array elements and most enumeration elements don't have back references, // so they don't tend to be involved in uniquing cycles and there is some // chance of merging them when linking together two modules. Only make // them distinct if they are ODR-uniqued. if (FullName.empty()) break; case llvm::dwarf::DW_TAG_structure_type: case llvm::dwarf::DW_TAG_union_type: case llvm::dwarf::DW_TAG_class_type: // Immediatley resolve to a distinct node. RealDecl = llvm::MDNode::replaceWithDistinct(llvm::TempDICompositeType(RealDecl)); break; } RegionMap[Ty->getDecl()].reset(RealDecl); TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl); if (const auto *TSpecial = dyn_cast(RD)) DBuilder.replaceArrays(RealDecl, llvm::DINodeArray(), CollectCXXTemplateParams(TSpecial, DefUnit)); return RealDecl; } void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD, llvm::DICompositeType *RealDecl) { // A class's primary base or the class itself contains the vtable. llvm::DICompositeType *ContainingType = nullptr; const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) { // Seek non-virtual primary base root. while (1) { const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase); const CXXRecordDecl *PBT = BRL.getPrimaryBase(); if (PBT && !BRL.isPrimaryBaseVirtual()) PBase = PBT; else break; } ContainingType = cast( getOrCreateType(QualType(PBase->getTypeForDecl(), 0), getOrCreateFile(RD->getLocation()))); } else if (RD->isDynamicClass()) ContainingType = RealDecl; DBuilder.replaceVTableHolder(RealDecl, ContainingType); } llvm::DIType *CGDebugInfo::CreateMemberType(llvm::DIFile *Unit, QualType FType, StringRef Name, uint64_t *Offset) { llvm::DIType *FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); uint64_t FieldSize = CGM.getContext().getTypeSize(FType); auto FieldAlign = getTypeAlignIfRequired(FType, CGM.getContext()); llvm::DIType *Ty = DBuilder.createMemberType(Unit, Name, Unit, 0, FieldSize, FieldAlign, *Offset, llvm::DINode::FlagZero, FieldTy); *Offset += FieldSize; return Ty; } void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit, StringRef &Name, StringRef &LinkageName, llvm::DIScope *&FDContext, llvm::DINodeArray &TParamsArray, llvm::DINode::DIFlags &Flags) { const auto *FD = cast(GD.getDecl()); Name = getFunctionName(FD); // Use mangled name as linkage name for C/C++ functions. if (FD->hasPrototype()) { LinkageName = CGM.getMangledName(GD); Flags |= llvm::DINode::FlagPrototyped; } // No need to replicate the linkage name if it isn't different from the // subprogram name, no need to have it at all unless coverage is enabled or // debug is set to more than just line tables or extra debug info is needed. if (LinkageName == Name || (!CGM.getCodeGenOpts().EmitGcovArcs && !CGM.getCodeGenOpts().EmitGcovNotes && !CGM.getCodeGenOpts().DebugInfoForProfiling && DebugKind <= codegenoptions::DebugLineTablesOnly)) LinkageName = StringRef(); if (DebugKind >= codegenoptions::LimitedDebugInfo) { if (const NamespaceDecl *NSDecl = - dyn_cast_or_null(FD->getLexicalDeclContext())) + dyn_cast_or_null(FD->getDeclContext())) FDContext = getOrCreateNamespace(NSDecl); else if (const RecordDecl *RDecl = dyn_cast_or_null(FD->getDeclContext())) { llvm::DIScope *Mod = getParentModuleOrNull(RDecl); FDContext = getContextDescriptor(RDecl, Mod ? Mod : TheCU); } // Check if it is a noreturn-marked function if (FD->isNoReturn()) Flags |= llvm::DINode::FlagNoReturn; // Collect template parameters. TParamsArray = CollectFunctionTemplateParams(FD, Unit); } } void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit, unsigned &LineNo, QualType &T, StringRef &Name, StringRef &LinkageName, llvm::DIScope *&VDContext) { Unit = getOrCreateFile(VD->getLocation()); LineNo = getLineNumber(VD->getLocation()); setLocation(VD->getLocation()); T = VD->getType(); if (T->isIncompleteArrayType()) { // CodeGen turns int[] into int[1] so we'll do the same here. llvm::APInt ConstVal(32, 1); QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } Name = VD->getName(); if (VD->getDeclContext() && !isa(VD->getDeclContext()) && !isa(VD->getDeclContext())) LinkageName = CGM.getMangledName(VD); if (LinkageName == Name) LinkageName = StringRef(); // Since we emit declarations (DW_AT_members) for static members, place the // definition of those static members in the namespace they were declared in // in the source code (the lexical decl context). // FIXME: Generalize this for even non-member global variables where the // declaration and definition may have different lexical decl contexts, once // we have support for emitting declarations of (non-member) global variables. const DeclContext *DC = VD->isStaticDataMember() ? VD->getLexicalDeclContext() : VD->getDeclContext(); // When a record type contains an in-line initialization of a static data // member, and the record type is marked as __declspec(dllexport), an implicit // definition of the member will be created in the record context. DWARF // doesn't seem to have a nice way to describe this in a form that consumers // are likely to understand, so fake the "normal" situation of a definition // outside the class by putting it in the global scope. if (DC->isRecord()) DC = CGM.getContext().getTranslationUnitDecl(); llvm::DIScope *Mod = getParentModuleOrNull(VD); VDContext = getContextDescriptor(cast(DC), Mod ? Mod : TheCU); } llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD, bool Stub) { llvm::DINodeArray TParamsArray; StringRef Name, LinkageName; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; SourceLocation Loc = GD.getDecl()->getLocation(); llvm::DIFile *Unit = getOrCreateFile(Loc); llvm::DIScope *DContext = Unit; unsigned Line = getLineNumber(Loc); collectFunctionDeclProps(GD, Unit, Name, LinkageName, DContext, TParamsArray, Flags); auto *FD = dyn_cast(GD.getDecl()); // Build function type. SmallVector ArgTypes; if (FD) for (const ParmVarDecl *Parm : FD->parameters()) ArgTypes.push_back(Parm->getType()); CallingConv CC = FD->getType()->castAs()->getCallConv(); QualType FnType = CGM.getContext().getFunctionType( FD->getReturnType(), ArgTypes, FunctionProtoType::ExtProtoInfo(CC)); if (Stub) { return DBuilder.createFunction( DContext, Name, LinkageName, Unit, Line, getOrCreateFunctionType(GD.getDecl(), FnType, Unit), !FD->isExternallyVisible(), /* isDefinition = */ true, 0, Flags, CGM.getLangOpts().Optimize, TParamsArray.get(), getFunctionDeclaration(FD)); } llvm::DISubprogram *SP = DBuilder.createTempFunctionFwdDecl( DContext, Name, LinkageName, Unit, Line, getOrCreateFunctionType(GD.getDecl(), FnType, Unit), !FD->isExternallyVisible(), /* isDefinition = */ false, 0, Flags, CGM.getLangOpts().Optimize, TParamsArray.get(), getFunctionDeclaration(FD)); const auto *CanonDecl = cast(FD->getCanonicalDecl()); FwdDeclReplaceMap.emplace_back(std::piecewise_construct, std::make_tuple(CanonDecl), std::make_tuple(SP)); return SP; } llvm::DISubprogram * CGDebugInfo::getFunctionForwardDeclaration(GlobalDecl GD) { return getFunctionFwdDeclOrStub(GD, /* Stub = */ false); } llvm::DISubprogram * CGDebugInfo::getFunctionStub(GlobalDecl GD) { return getFunctionFwdDeclOrStub(GD, /* Stub = */ true); } llvm::DIGlobalVariable * CGDebugInfo::getGlobalVariableForwardDeclaration(const VarDecl *VD) { QualType T; StringRef Name, LinkageName; SourceLocation Loc = VD->getLocation(); llvm::DIFile *Unit = getOrCreateFile(Loc); llvm::DIScope *DContext = Unit; unsigned Line = getLineNumber(Loc); collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, DContext); auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); auto *GV = DBuilder.createTempGlobalVariableFwdDecl( DContext, Name, LinkageName, Unit, Line, getOrCreateType(T, Unit), !VD->isExternallyVisible(), nullptr, Align); FwdDeclReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(cast(VD->getCanonicalDecl())), std::make_tuple(static_cast(GV))); return GV; } llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) { // We only need a declaration (not a definition) of the type - so use whatever // we would otherwise do to get a type for a pointee. (forward declarations in // limited debug info, full definitions (if the type definition is available) // in unlimited debug info) if (const auto *TD = dyn_cast(D)) return getOrCreateType(CGM.getContext().getTypeDeclType(TD), getOrCreateFile(TD->getLocation())); auto I = DeclCache.find(D->getCanonicalDecl()); if (I != DeclCache.end()) { auto N = I->second; if (auto *GVE = dyn_cast_or_null(N)) return GVE->getVariable(); return dyn_cast_or_null(N); } // No definition for now. Emit a forward definition that might be // merged with a potential upcoming definition. if (const auto *FD = dyn_cast(D)) return getFunctionForwardDeclaration(FD); else if (const auto *VD = dyn_cast(D)) return getGlobalVariableForwardDeclaration(VD); return nullptr; } llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) { if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly) return nullptr; const auto *FD = dyn_cast(D); if (!FD) return nullptr; // Setup context. auto *S = getDeclContextDescriptor(D); auto MI = SPCache.find(FD->getCanonicalDecl()); if (MI == SPCache.end()) { if (const auto *MD = dyn_cast(FD->getCanonicalDecl())) { return CreateCXXMemberFunction(MD, getOrCreateFile(MD->getLocation()), cast(S)); } } if (MI != SPCache.end()) { auto *SP = dyn_cast_or_null(MI->second); if (SP && !SP->isDefinition()) return SP; } for (auto NextFD : FD->redecls()) { auto MI = SPCache.find(NextFD->getCanonicalDecl()); if (MI != SPCache.end()) { auto *SP = dyn_cast_or_null(MI->second); if (SP && !SP->isDefinition()) return SP; } } return nullptr; } // getOrCreateFunctionType - Construct type. If it is a c++ method, include // implicit parameter "this". llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F) { if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly) // Create fake but valid subroutine type. Otherwise -verify would fail, and // subprogram DIE will miss DW_AT_decl_file and DW_AT_decl_line fields. return DBuilder.createSubroutineType(DBuilder.getOrCreateTypeArray(None)); if (const auto *Method = dyn_cast(D)) return getOrCreateMethodType(Method, F); const auto *FTy = FnType->getAs(); CallingConv CC = FTy ? FTy->getCallConv() : CallingConv::CC_C; if (const auto *OMethod = dyn_cast(D)) { // Add "self" and "_cmd" SmallVector Elts; // First element is always return type. For 'void' functions it is NULL. QualType ResultTy = OMethod->getReturnType(); // Replace the instancetype keyword with the actual type. if (ResultTy == CGM.getContext().getObjCInstanceType()) ResultTy = CGM.getContext().getPointerType( QualType(OMethod->getClassInterface()->getTypeForDecl(), 0)); Elts.push_back(getOrCreateType(ResultTy, F)); // "self" pointer is always first argument. QualType SelfDeclTy; if (auto *SelfDecl = OMethod->getSelfDecl()) SelfDeclTy = SelfDecl->getType(); else if (auto *FPT = dyn_cast(FnType)) if (FPT->getNumParams() > 1) SelfDeclTy = FPT->getParamType(0); if (!SelfDeclTy.isNull()) Elts.push_back(CreateSelfType(SelfDeclTy, getOrCreateType(SelfDeclTy, F))); // "_cmd" pointer is always second argument. Elts.push_back(DBuilder.createArtificialType( getOrCreateType(CGM.getContext().getObjCSelType(), F))); // Get rest of the arguments. for (const auto *PI : OMethod->parameters()) Elts.push_back(getOrCreateType(PI->getType(), F)); // Variadic methods need a special marker at the end of the type list. if (OMethod->isVariadic()) Elts.push_back(DBuilder.createUnspecifiedParameter()); llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts); return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero, getDwarfCC(CC)); } // Handle variadic function types; they need an additional // unspecified parameter. if (const auto *FD = dyn_cast(D)) if (FD->isVariadic()) { SmallVector EltTys; EltTys.push_back(getOrCreateType(FD->getReturnType(), F)); if (const auto *FPT = dyn_cast(FnType)) for (QualType ParamType : FPT->param_types()) EltTys.push_back(getOrCreateType(ParamType, F)); EltTys.push_back(DBuilder.createUnspecifiedParameter()); llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys); return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero, getDwarfCC(CC)); } return cast(getOrCreateType(FnType, F)); } void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, SourceLocation ScopeLoc, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { StringRef Name; StringRef LinkageName; FnBeginRegionCount.push_back(LexicalBlockStack.size()); const Decl *D = GD.getDecl(); bool HasDecl = (D != nullptr); llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; llvm::DIFile *Unit = getOrCreateFile(Loc); llvm::DIScope *FDContext = Unit; llvm::DINodeArray TParamsArray; if (!HasDecl) { // Use llvm function name. LinkageName = Fn->getName(); } else if (const auto *FD = dyn_cast(D)) { // If there is a subprogram for this function available then use it. auto FI = SPCache.find(FD->getCanonicalDecl()); if (FI != SPCache.end()) { auto *SP = dyn_cast_or_null(FI->second); if (SP && SP->isDefinition()) { LexicalBlockStack.emplace_back(SP); RegionMap[D].reset(SP); return; } } collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext, TParamsArray, Flags); } else if (const auto *OMD = dyn_cast(D)) { Name = getObjCMethodName(OMD); Flags |= llvm::DINode::FlagPrototyped; } else { // Use llvm function name. Name = Fn->getName(); Flags |= llvm::DINode::FlagPrototyped; } if (Name.startswith("\01")) Name = Name.substr(1); if (!HasDecl || D->isImplicit()) { Flags |= llvm::DINode::FlagArtificial; // Artificial functions should not silently reuse CurLoc. CurLoc = SourceLocation(); } unsigned LineNo = getLineNumber(Loc); unsigned ScopeLine = getLineNumber(ScopeLoc); // FIXME: The function declaration we're constructing here is mostly reusing // declarations from CXXMethodDecl and not constructing new ones for arbitrary // FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for // all subprograms instead of the actual context since subprogram definitions // are emitted as CU level entities by the backend. llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, getOrCreateFunctionType(D, FnType, Unit), Fn->hasLocalLinkage(), true /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, TParamsArray.get(), getFunctionDeclaration(D)); Fn->setSubprogram(SP); // We might get here with a VarDecl in the case we're generating // code for the initialization of globals. Do not record these decls // as they will overwrite the actual VarDecl Decl in the cache. if (HasDecl && isa(D)) DeclCache[D->getCanonicalDecl()].reset(SP); // Push the function onto the lexical block stack. LexicalBlockStack.emplace_back(SP); if (HasDecl) RegionMap[D].reset(SP); } void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType) { StringRef Name; StringRef LinkageName; const Decl *D = GD.getDecl(); if (!D) return; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; llvm::DIFile *Unit = getOrCreateFile(Loc); llvm::DIScope *FDContext = getDeclContextDescriptor(D); llvm::DINodeArray TParamsArray; if (isa(D)) { // If there is a DISubprogram for this function available then use it. collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext, TParamsArray, Flags); } else if (const auto *OMD = dyn_cast(D)) { Name = getObjCMethodName(OMD); Flags |= llvm::DINode::FlagPrototyped; } else { llvm_unreachable("not a function or ObjC method"); } if (!Name.empty() && Name[0] == '\01') Name = Name.substr(1); if (D->isImplicit()) { Flags |= llvm::DINode::FlagArtificial; // Artificial functions without a location should not silently reuse CurLoc. if (Loc.isInvalid()) CurLoc = SourceLocation(); } unsigned LineNo = getLineNumber(Loc); unsigned ScopeLine = 0; DBuilder.retainType(DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, getOrCreateFunctionType(D, FnType, Unit), false /*internalLinkage*/, false /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, TParamsArray.get(), getFunctionDeclaration(D))); } void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) { const auto *FD = cast(GD.getDecl()); // If there is a subprogram for this function available then use it. auto FI = SPCache.find(FD->getCanonicalDecl()); llvm::DISubprogram *SP = nullptr; if (FI != SPCache.end()) SP = dyn_cast_or_null(FI->second); if (!SP) SP = getFunctionStub(GD); FnBeginRegionCount.push_back(LexicalBlockStack.size()); LexicalBlockStack.emplace_back(SP); setInlinedAt(Builder.getCurrentDebugLocation()); EmitLocation(Builder, FD->getLocation()); } void CGDebugInfo::EmitInlineFunctionEnd(CGBuilderTy &Builder) { assert(CurInlinedAt && "unbalanced inline scope stack"); EmitFunctionEnd(Builder); setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt()); } void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { // Update our current location setLocation(Loc); if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; llvm::MDNode *Scope = LexicalBlockStack.back(); Builder.SetCurrentDebugLocation(llvm::DebugLoc::get( getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope, CurInlinedAt)); } void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { llvm::MDNode *Back = nullptr; if (!LexicalBlockStack.empty()) Back = LexicalBlockStack.back().get(); LexicalBlockStack.emplace_back(DBuilder.createLexicalBlock( cast(Back), getOrCreateFile(CurLoc), getLineNumber(CurLoc), getColumnNumber(CurLoc))); } void CGDebugInfo::AppendAddressSpaceXDeref( unsigned AddressSpace, SmallVectorImpl &Expr) const { Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); if (!DWARFAddressSpace) return; Expr.push_back(llvm::dwarf::DW_OP_constu); Expr.push_back(DWARFAddressSpace.getValue()); Expr.push_back(llvm::dwarf::DW_OP_swap); Expr.push_back(llvm::dwarf::DW_OP_xderef); } void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) { // Set our current location. setLocation(Loc); // Emit a line table change for the current location inside the new scope. Builder.SetCurrentDebugLocation( llvm::DebugLoc::get(getLineNumber(Loc), getColumnNumber(Loc), LexicalBlockStack.back(), CurInlinedAt)); if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; // Create a new lexical block and push it on the stack. CreateLexicalBlock(Loc); } void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) { assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); // Provide an entry in the line table for the end of the block. EmitLocation(Builder, Loc); if (DebugKind <= codegenoptions::DebugLineTablesOnly) return; LexicalBlockStack.pop_back(); } void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); unsigned RCount = FnBeginRegionCount.back(); assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch"); // Pop all regions for this function. while (LexicalBlockStack.size() != RCount) { // Provide an entry in the line table for the end of the block. EmitLocation(Builder, CurLoc); LexicalBlockStack.pop_back(); } FnBeginRegionCount.pop_back(); } llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, uint64_t *XOffset) { SmallVector EltTys; QualType FType; uint64_t FieldSize, FieldOffset; uint32_t FieldAlign; llvm::DIFile *Unit = getOrCreateFile(VD->getLocation()); QualType Type = VD->getType(); FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset)); FType = CGM.getContext().IntTy; EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD); if (HasCopyAndDispose) { FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); EltTys.push_back( CreateMemberType(Unit, FType, "__copy_helper", &FieldOffset)); EltTys.push_back( CreateMemberType(Unit, FType, "__destroy_helper", &FieldOffset)); } bool HasByrefExtendedLayout; Qualifiers::ObjCLifetime Lifetime; if (CGM.getContext().getByrefLifetime(Type, Lifetime, HasByrefExtendedLayout) && HasByrefExtendedLayout) { FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); EltTys.push_back( CreateMemberType(Unit, FType, "__byref_variable_layout", &FieldOffset)); } CharUnits Align = CGM.getContext().getDeclAlign(VD); if (Align > CGM.getContext().toCharUnitsFromBits( CGM.getTarget().getPointerAlign(0))) { CharUnits FieldOffsetInBytes = CGM.getContext().toCharUnitsFromBits(FieldOffset); CharUnits AlignedOffsetInBytes = FieldOffsetInBytes.alignTo(Align); CharUnits NumPaddingBytes = AlignedOffsetInBytes - FieldOffsetInBytes; if (NumPaddingBytes.isPositive()) { llvm::APInt pad(32, NumPaddingBytes.getQuantity()); FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset)); } } FType = Type; llvm::DIType *FieldTy = getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = CGM.getContext().toBits(Align); *XOffset = FieldOffset; FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit, 0, FieldSize, FieldAlign, FieldOffset, llvm::DINode::FlagZero, FieldTy); EltTys.push_back(FieldTy); FieldOffset += FieldSize; llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); llvm::DINode::DIFlags Flags = llvm::DINode::FlagBlockByrefStruct; return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags, nullptr, Elements); } void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage, llvm::Optional ArgNo, CGBuilderTy &Builder) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (VD->hasAttr()) return; bool Unwritten = VD->isImplicit() || (isa(VD->getDeclContext()) && cast(VD->getDeclContext())->isImplicit()); llvm::DIFile *Unit = nullptr; if (!Unwritten) Unit = getOrCreateFile(VD->getLocation()); llvm::DIType *Ty; uint64_t XOffset = 0; if (VD->hasAttr()) Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); else Ty = getOrCreateType(VD->getType(), Unit); // If there is no debug info for this type then do not emit debug info // for this variable. if (!Ty) return; // Get location information. unsigned Line = 0; unsigned Column = 0; if (!Unwritten) { Line = getLineNumber(VD->getLocation()); Column = getColumnNumber(VD->getLocation()); } SmallVector Expr; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (VD->isImplicit()) Flags |= llvm::DINode::FlagArtificial; auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType()); AppendAddressSpaceXDeref(AddressSpace, Expr); // If this is the first argument and it is implicit then // give it an object pointer flag. // FIXME: There has to be a better way to do this, but for static // functions there won't be an implicit param at arg1 and // otherwise it is 'self' or 'this'. if (isa(VD) && ArgNo && *ArgNo == 1) Flags |= llvm::DINode::FlagObjectPointer; // Note: Older versions of clang used to emit byval references with an extra // DW_OP_deref, because they referenced the IR arg directly instead of // referencing an alloca. Newer versions of LLVM don't treat allocas // differently from other function arguments when used in a dbg.declare. auto *Scope = cast(LexicalBlockStack.back()); StringRef Name = VD->getName(); if (!Name.empty()) { if (VD->hasAttr()) { // Here, we need an offset *into* the alloca. CharUnits offset = CharUnits::fromQuantity(32); Expr.push_back(llvm::dwarf::DW_OP_plus); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits( CGM.getTarget().getPointerWidth(0)); Expr.push_back(offset.getQuantity()); Expr.push_back(llvm::dwarf::DW_OP_deref); Expr.push_back(llvm::dwarf::DW_OP_plus); // offset of x field offset = CGM.getContext().toCharUnitsFromBits(XOffset); Expr.push_back(offset.getQuantity()); } } else if (const auto *RT = dyn_cast(VD->getType())) { // If VD is an anonymous union then Storage represents value for // all union fields. const auto *RD = cast(RT->getDecl()); if (RD->isUnion() && RD->isAnonymousStructOrUnion()) { // GDB has trouble finding local variables in anonymous unions, so we emit // artifical local variables for each of the members. // // FIXME: Remove this code as soon as GDB supports this. // The debug info verifier in LLVM operates based on the assumption that a // variable has the same size as its storage and we had to disable the check // for artificial variables. for (const auto *Field : RD->fields()) { llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit); StringRef FieldName = Field->getName(); // Ignore unnamed fields. Do not ignore unnamed records. if (FieldName.empty() && !isa(Field->getType())) continue; // Use VarDecl's Tag, Scope and Line number. auto FieldAlign = getDeclAlignIfRequired(Field, CGM.getContext()); auto *D = DBuilder.createAutoVariable( Scope, FieldName, Unit, Line, FieldTy, CGM.getLangOpts().Optimize, Flags | llvm::DINode::FlagArtificial, FieldAlign); // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare( Storage, D, DBuilder.createExpression(Expr), llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt), Builder.GetInsertBlock()); } } } // Create the descriptor for the variable. auto *D = ArgNo ? DBuilder.createParameterVariable( Scope, Name, *ArgNo, Unit, Line, Ty, CGM.getLangOpts().Optimize, Flags) : DBuilder.createAutoVariable(Scope, Name, Unit, Line, Ty, CGM.getLangOpts().Optimize, Flags, Align); // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr), llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt), Builder.GetInsertBlock()); } void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); EmitDeclare(VD, Storage, llvm::None, Builder); } llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType *Ty) { llvm::DIType *CachedTy = getTypeOrNull(QualTy); if (CachedTy) Ty = CachedTy; return DBuilder.createObjectPointerType(Ty); } void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (Builder.GetInsertBlock() == nullptr) return; if (VD->hasAttr()) return; bool isByRef = VD->hasAttr(); uint64_t XOffset = 0; llvm::DIFile *Unit = getOrCreateFile(VD->getLocation()); llvm::DIType *Ty; if (isByRef) Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); else Ty = getOrCreateType(VD->getType(), Unit); // Self is passed along as an implicit non-arg variable in a // block. Mark it as the object pointer. if (isa(VD) && VD->getName() == "self") Ty = CreateSelfType(VD->getType(), Ty); // Get location information. unsigned Line = getLineNumber(VD->getLocation()); unsigned Column = getColumnNumber(VD->getLocation()); const llvm::DataLayout &target = CGM.getDataLayout(); CharUnits offset = CharUnits::fromQuantity( target.getStructLayout(blockInfo.StructureType) ->getElementOffset(blockInfo.getCapture(VD).getIndex())); SmallVector addr; addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus); addr.push_back(offset.getQuantity()); if (isByRef) { addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits(0)); addr.push_back(offset.getQuantity()); addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus); // offset of x field offset = CGM.getContext().toCharUnitsFromBits(XOffset); addr.push_back(offset.getQuantity()); } // Create the descriptor for the variable. auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); auto *D = DBuilder.createAutoVariable( cast(LexicalBlockStack.back()), VD->getName(), Unit, Line, Ty, false, llvm::DINode::FlagZero, Align); // Insert an llvm.dbg.declare into the current block. auto DL = llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back(), CurInlinedAt); auto *Expr = DBuilder.createExpression(addr); if (InsertPoint) DBuilder.insertDeclare(Storage, D, Expr, DL, InsertPoint); else DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock()); } void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); EmitDeclare(VD, AI, ArgNo, Builder); } namespace { struct BlockLayoutChunk { uint64_t OffsetInBits; const BlockDecl::Capture *Capture; }; bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) { return l.OffsetInBits < r.OffsetInBits; } } void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, llvm::Value *Arg, unsigned ArgNo, llvm::Value *LocalAddr, CGBuilderTy &Builder) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); ASTContext &C = CGM.getContext(); const BlockDecl *blockDecl = block.getBlockDecl(); // Collect some general information about the block's location. SourceLocation loc = blockDecl->getCaretLocation(); llvm::DIFile *tunit = getOrCreateFile(loc); unsigned line = getLineNumber(loc); unsigned column = getColumnNumber(loc); // Build the debug-info type for the block literal. getDeclContextDescriptor(blockDecl); const llvm::StructLayout *blockLayout = CGM.getDataLayout().getStructLayout(block.StructureType); SmallVector fields; fields.push_back(createFieldType("__isa", C.VoidPtrTy, loc, AS_public, blockLayout->getElementOffsetInBits(0), tunit, tunit)); fields.push_back(createFieldType("__flags", C.IntTy, loc, AS_public, blockLayout->getElementOffsetInBits(1), tunit, tunit)); fields.push_back(createFieldType("__reserved", C.IntTy, loc, AS_public, blockLayout->getElementOffsetInBits(2), tunit, tunit)); auto *FnTy = block.getBlockExpr()->getFunctionType(); auto FnPtrType = CGM.getContext().getPointerType(FnTy->desugar()); fields.push_back(createFieldType("__FuncPtr", FnPtrType, loc, AS_public, blockLayout->getElementOffsetInBits(3), tunit, tunit)); fields.push_back(createFieldType( "__descriptor", C.getPointerType(block.NeedsCopyDispose ? C.getBlockDescriptorExtendedType() : C.getBlockDescriptorType()), loc, AS_public, blockLayout->getElementOffsetInBits(4), tunit, tunit)); // We want to sort the captures by offset, not because DWARF // requires this, but because we're paranoid about debuggers. SmallVector chunks; // 'this' capture. if (blockDecl->capturesCXXThis()) { BlockLayoutChunk chunk; chunk.OffsetInBits = blockLayout->getElementOffsetInBits(block.CXXThisIndex); chunk.Capture = nullptr; chunks.push_back(chunk); } // Variable captures. for (const auto &capture : blockDecl->captures()) { const VarDecl *variable = capture.getVariable(); const CGBlockInfo::Capture &captureInfo = block.getCapture(variable); // Ignore constant captures. if (captureInfo.isConstant()) continue; BlockLayoutChunk chunk; chunk.OffsetInBits = blockLayout->getElementOffsetInBits(captureInfo.getIndex()); chunk.Capture = &capture; chunks.push_back(chunk); } // Sort by offset. llvm::array_pod_sort(chunks.begin(), chunks.end()); for (const BlockLayoutChunk &Chunk : chunks) { uint64_t offsetInBits = Chunk.OffsetInBits; const BlockDecl::Capture *capture = Chunk.Capture; // If we have a null capture, this must be the C++ 'this' capture. if (!capture) { QualType type; if (auto *Method = cast_or_null(blockDecl->getNonClosureContext())) type = Method->getThisType(C); else if (auto *RDecl = dyn_cast(blockDecl->getParent())) type = QualType(RDecl->getTypeForDecl(), 0); else llvm_unreachable("unexpected block declcontext"); fields.push_back(createFieldType("this", type, loc, AS_public, offsetInBits, tunit, tunit)); continue; } const VarDecl *variable = capture->getVariable(); StringRef name = variable->getName(); llvm::DIType *fieldType; if (capture->isByRef()) { TypeInfo PtrInfo = C.getTypeInfo(C.VoidPtrTy); auto Align = PtrInfo.AlignIsRequired ? PtrInfo.Align : 0; // FIXME: this creates a second copy of this type! uint64_t xoffset; fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset); fieldType = DBuilder.createPointerType(fieldType, PtrInfo.Width); fieldType = DBuilder.createMemberType(tunit, name, tunit, line, PtrInfo.Width, Align, offsetInBits, llvm::DINode::FlagZero, fieldType); } else { auto Align = getDeclAlignIfRequired(variable, CGM.getContext()); fieldType = createFieldType(name, variable->getType(), loc, AS_public, offsetInBits, Align, tunit, tunit); } fields.push_back(fieldType); } SmallString<36> typeName; llvm::raw_svector_ostream(typeName) << "__block_literal_" << CGM.getUniqueBlockCount(); llvm::DINodeArray fieldsArray = DBuilder.getOrCreateArray(fields); llvm::DIType *type = DBuilder.createStructType(tunit, typeName.str(), tunit, line, CGM.getContext().toBits(block.BlockSize), 0, llvm::DINode::FlagZero, nullptr, fieldsArray); type = DBuilder.createPointerType(type, CGM.PointerWidthInBits); // Get overall information about the block. llvm::DINode::DIFlags flags = llvm::DINode::FlagArtificial; auto *scope = cast(LexicalBlockStack.back()); // Create the descriptor for the parameter. auto *debugVar = DBuilder.createParameterVariable( scope, Arg->getName(), ArgNo, tunit, line, type, CGM.getLangOpts().Optimize, flags); if (LocalAddr) { // Insert an llvm.dbg.value into the current block. DBuilder.insertDbgValueIntrinsic( LocalAddr, 0, debugVar, DBuilder.createExpression(), llvm::DebugLoc::get(line, column, scope, CurInlinedAt), Builder.GetInsertBlock()); } // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare(Arg, debugVar, DBuilder.createExpression(), llvm::DebugLoc::get(line, column, scope, CurInlinedAt), Builder.GetInsertBlock()); } llvm::DIDerivedType * CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) { if (!D->isStaticDataMember()) return nullptr; auto MI = StaticDataMemberCache.find(D->getCanonicalDecl()); if (MI != StaticDataMemberCache.end()) { assert(MI->second && "Static data member declaration should still exist"); return MI->second; } // If the member wasn't found in the cache, lazily construct and add it to the // type (used when a limited form of the type is emitted). auto DC = D->getDeclContext(); auto *Ctxt = cast(getDeclContextDescriptor(D)); return CreateRecordStaticField(D, Ctxt, cast(DC)); } llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls( const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo, StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext) { llvm::DIGlobalVariableExpression *GVE = nullptr; for (const auto *Field : RD->fields()) { llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit); StringRef FieldName = Field->getName(); // Ignore unnamed fields, but recurse into anonymous records. if (FieldName.empty()) { if (const auto *RT = dyn_cast(Field->getType())) GVE = CollectAnonRecordDecls(RT->getDecl(), Unit, LineNo, LinkageName, Var, DContext); continue; } // Use VarDecl's Tag, Scope and Line number. GVE = DBuilder.createGlobalVariableExpression( DContext, FieldName, LinkageName, Unit, LineNo, FieldTy, Var->hasLocalLinkage()); Var->addDebugInfo(GVE); } return GVE; } void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); if (D->hasAttr()) return; // If we already created a DIGlobalVariable for this declaration, just attach // it to the llvm::GlobalVariable. auto Cached = DeclCache.find(D->getCanonicalDecl()); if (Cached != DeclCache.end()) return Var->addDebugInfo( cast(Cached->second)); // Create global variable debug descriptor. llvm::DIFile *Unit = nullptr; llvm::DIScope *DContext = nullptr; unsigned LineNo; StringRef DeclName, LinkageName; QualType T; collectVarDeclProps(D, Unit, LineNo, T, DeclName, LinkageName, DContext); // Attempt to store one global variable for the declaration - even if we // emit a lot of fields. llvm::DIGlobalVariableExpression *GVE = nullptr; // If this is an anonymous union then we'll want to emit a global // variable for each member of the anonymous union so that it's possible // to find the name of any field in the union. if (T->isUnionType() && DeclName.empty()) { const RecordDecl *RD = T->castAs()->getDecl(); assert(RD->isAnonymousStructOrUnion() && "unnamed non-anonymous struct or union?"); GVE = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext); } else { auto Align = getDeclAlignIfRequired(D, CGM.getContext()); SmallVector Expr; unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(D->getType()); AppendAddressSpaceXDeref(AddressSpace, Expr); GVE = DBuilder.createGlobalVariableExpression( DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), Var->hasLocalLinkage(), Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), Align); Var->addDebugInfo(GVE); } DeclCache[D->getCanonicalDecl()].reset(GVE); } void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); if (VD->hasAttr()) return; auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); // Create the descriptor for the variable. llvm::DIFile *Unit = getOrCreateFile(VD->getLocation()); StringRef Name = VD->getName(); llvm::DIType *Ty = getOrCreateType(VD->getType(), Unit); if (const auto *ECD = dyn_cast(VD)) { const auto *ED = cast(ECD->getDeclContext()); assert(isa(ED->getTypeForDecl()) && "Enum without EnumType?"); Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit); } // Do not use global variables for enums. // // FIXME: why not? if (Ty->getTag() == llvm::dwarf::DW_TAG_enumeration_type) return; // Do not emit separate definitions for function local const/statics. if (isa(VD->getDeclContext())) return; VD = cast(VD->getCanonicalDecl()); auto *VarD = cast(VD); if (VarD->isStaticDataMember()) { auto *RD = cast(VarD->getDeclContext()); getDeclContextDescriptor(VarD); // Ensure that the type is retained even though it's otherwise unreferenced. // // FIXME: This is probably unnecessary, since Ty should reference RD // through its scope. RetainedTypes.push_back( CGM.getContext().getRecordType(RD).getAsOpaquePtr()); return; } llvm::DIScope *DContext = getDeclContextDescriptor(VD); auto &GV = DeclCache[VD]; if (GV) return; llvm::DIExpression *InitExpr = nullptr; if (CGM.getContext().getTypeSize(VD->getType()) <= 64) { // FIXME: Add a representation for integer constants wider than 64 bits. if (Init.isInt()) InitExpr = DBuilder.createConstantValueExpression(Init.getInt().getExtValue()); else if (Init.isFloat()) InitExpr = DBuilder.createConstantValueExpression( Init.getFloat().bitcastToAPInt().getZExtValue()); } GV.reset(DBuilder.createGlobalVariableExpression( DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty, true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), Align)); } llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { if (!LexicalBlockStack.empty()) return LexicalBlockStack.back(); llvm::DIScope *Mod = getParentModuleOrNull(D); return getContextDescriptor(D, Mod ? Mod : TheCU); } void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) { if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) return; const NamespaceDecl *NSDecl = UD.getNominatedNamespace(); if (!NSDecl->isAnonymousNamespace() || CGM.getCodeGenOpts().DebugExplicitImport) { DBuilder.createImportedModule( getCurrentContextDescriptor(cast(UD.getDeclContext())), getOrCreateNamespace(NSDecl), getLineNumber(UD.getLocation())); } } void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) { if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) return; assert(UD.shadow_size() && "We shouldn't be codegening an invalid UsingDecl containing no decls"); // Emitting one decl is sufficient - debuggers can detect that this is an // overloaded name & provide lookup for all the overloads. const UsingShadowDecl &USD = **UD.shadow_begin(); // FIXME: Skip functions with undeduced auto return type for now since we // don't currently have the plumbing for separate declarations & definitions // of free functions and mismatched types (auto in the declaration, concrete // return type in the definition) if (const auto *FD = dyn_cast(USD.getUnderlyingDecl())) if (const auto *AT = FD->getType()->getAs()->getContainedAutoType()) if (AT->getDeducedType().isNull()) return; if (llvm::DINode *Target = getDeclarationOrDefinition(USD.getUnderlyingDecl())) DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(USD.getDeclContext())), Target, getLineNumber(USD.getLocation())); } void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) { if (CGM.getCodeGenOpts().getDebuggerTuning() != llvm::DebuggerKind::LLDB) return; if (Module *M = ID.getImportedModule()) { auto Info = ExternalASTSource::ASTSourceDescriptor(*M); DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(ID.getDeclContext())), getOrCreateModuleRef(Info, DebugTypeExtRefs), getLineNumber(ID.getLocation())); } } llvm::DIImportedEntity * CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) { if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) return nullptr; auto &VH = NamespaceAliasCache[&NA]; if (VH) return cast(VH); llvm::DIImportedEntity *R; if (const auto *Underlying = dyn_cast(NA.getAliasedNamespace())) // This could cache & dedup here rather than relying on metadata deduping. R = DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(NA.getDeclContext())), EmitNamespaceAlias(*Underlying), getLineNumber(NA.getLocation()), NA.getName()); else R = DBuilder.createImportedDeclaration( getCurrentContextDescriptor(cast(NA.getDeclContext())), getOrCreateNamespace(cast(NA.getAliasedNamespace())), getLineNumber(NA.getLocation()), NA.getName()); VH.reset(R); return R; } llvm::DINamespace * CGDebugInfo::getOrCreateNamespace(const NamespaceDecl *NSDecl) { // Don't canonicalize the NamespaceDecl here: The DINamespace will be uniqued // if necessary, and this way multiple declarations of the same namespace in // different parent modules stay distinct. auto I = NamespaceCache.find(NSDecl); if (I != NamespaceCache.end()) return cast(I->second); llvm::DIScope *Context = getDeclContextDescriptor(NSDecl); // Don't trust the context if it is a DIModule (see comment above). llvm::DINamespace *NS = DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline()); NamespaceCache[NSDecl].reset(NS); return NS; } void CGDebugInfo::setDwoId(uint64_t Signature) { assert(TheCU && "no main compile unit"); TheCU->setDWOId(Signature); } void CGDebugInfo::finalize() { // Creating types might create further types - invalidating the current // element and the size(), so don't cache/reference them. for (size_t i = 0; i != ObjCInterfaceCache.size(); ++i) { ObjCInterfaceCacheEntry E = ObjCInterfaceCache[i]; llvm::DIType *Ty = E.Type->getDecl()->getDefinition() ? CreateTypeDefinition(E.Type, E.Unit) : E.Decl; DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty); } for (auto p : ReplaceMap) { assert(p.second); auto *Ty = cast(p.second); assert(Ty->isForwardDecl()); auto it = TypeCache.find(p.first); assert(it != TypeCache.end()); assert(it->second); DBuilder.replaceTemporary(llvm::TempDIType(Ty), cast(it->second)); } for (const auto &p : FwdDeclReplaceMap) { assert(p.second); llvm::TempMDNode FwdDecl(cast(p.second)); llvm::Metadata *Repl; auto it = DeclCache.find(p.first); // If there has been no definition for the declaration, call RAUW // with ourselves, that will destroy the temporary MDNode and // replace it with a standard one, avoiding leaking memory. if (it == DeclCache.end()) Repl = p.second; else Repl = it->second; if (auto *GVE = dyn_cast_or_null(Repl)) Repl = GVE->getVariable(); DBuilder.replaceTemporary(std::move(FwdDecl), cast(Repl)); } // We keep our own list of retained types, because we need to look // up the final type in the type cache. for (auto &RT : RetainedTypes) if (auto MD = TypeCache[RT]) DBuilder.retainType(cast(MD)); DBuilder.finalize(); } void CGDebugInfo::EmitExplicitCastType(QualType Ty) { if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) return; if (auto *DieTy = getOrCreateType(Ty, getOrCreateMainFile())) // Don't ignore in case of explicit cast where it is referenced indirectly. DBuilder.retainType(DieTy); } llvm::DebugLoc CGDebugInfo::SourceLocToDebugLoc(SourceLocation Loc) { if (LexicalBlockStack.empty()) return llvm::DebugLoc(); llvm::MDNode *Scope = LexicalBlockStack.back(); return llvm::DebugLoc::get( getLineNumber(Loc), getColumnNumber(Loc), Scope); } Index: vendor/clang/dist/lib/Driver/ToolChains/MSVC.cpp =================================================================== --- vendor/clang/dist/lib/Driver/ToolChains/MSVC.cpp (revision 318415) +++ vendor/clang/dist/lib/Driver/ToolChains/MSVC.cpp (revision 318416) @@ -1,1421 +1,1428 @@ //===--- ToolChains.cpp - ToolChain Implementations -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "MSVC.h" #include "CommonArgs.h" #include "Darwin.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Version.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include // Include the necessary headers to interface with the Windows registry and // environment. #if defined(LLVM_ON_WIN32) #define USE_WIN32 #endif #ifdef USE_WIN32 #define WIN32_LEAN_AND_MEAN #define NOGDI #ifndef NOMINMAX #define NOMINMAX #endif #include #endif #ifdef _MSC_VER // Don't support SetupApi on MinGW. #define USE_MSVC_SETUP_API // Make sure this comes before MSVCSetupApi.h #include #include "MSVCSetupApi.h" #include "llvm/Support/COM.h" _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); #endif using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; // Defined below. // Forward declare this so there aren't too many things above the constructor. static bool getSystemRegistryString(const char *keyPath, const char *valueName, std::string &value, std::string *phValue); // Check various environment variables to try and find a toolchain. static bool findVCToolChainViaEnvironment(std::string &Path, bool &IsVS2017OrNewer) { // These variables are typically set by vcvarsall.bat // when launching a developer command prompt. if (llvm::Optional VCToolsInstallDir = llvm::sys::Process::GetEnv("VCToolsInstallDir")) { // This is only set by newer Visual Studios, and it leads straight to // the toolchain directory. Path = std::move(*VCToolsInstallDir); IsVS2017OrNewer = true; return true; } if (llvm::Optional VCInstallDir = llvm::sys::Process::GetEnv("VCINSTALLDIR")) { // If the previous variable isn't set but this one is, then we've found // an older Visual Studio. This variable is set by newer Visual Studios too, // so this check has to appear second. // In older Visual Studios, the VC directory is the toolchain. Path = std::move(*VCInstallDir); IsVS2017OrNewer = false; return true; } // We couldn't find any VC environment variables. Let's walk through PATH and // see if it leads us to a VC toolchain bin directory. If it does, pick the // first one that we find. if (llvm::Optional PathEnv = llvm::sys::Process::GetEnv("PATH")) { llvm::SmallVector PathEntries; llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator); for (llvm::StringRef PathEntry : PathEntries) { if (PathEntry.empty()) continue; llvm::SmallString<256> ExeTestPath; // If cl.exe doesn't exist, then this definitely isn't a VC toolchain. ExeTestPath = PathEntry; llvm::sys::path::append(ExeTestPath, "cl.exe"); if (!llvm::sys::fs::exists(ExeTestPath)) continue; // cl.exe existing isn't a conclusive test for a VC toolchain; clang also // has a cl.exe. So let's check for link.exe too. ExeTestPath = PathEntry; llvm::sys::path::append(ExeTestPath, "link.exe"); if (!llvm::sys::fs::exists(ExeTestPath)) continue; // whatever/VC/bin --> old toolchain, VC dir is toolchain dir. - if (llvm::sys::path::filename(PathEntry) == "bin") { - llvm::StringRef ParentPath = llvm::sys::path::parent_path(PathEntry); + llvm::StringRef TestPath = PathEntry; + bool IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin"); + if (!IsBin) { + // Strip any architecture subdir like "amd64". + TestPath = llvm::sys::path::parent_path(TestPath); + IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin"); + } + if (IsBin) { + llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath); if (llvm::sys::path::filename(ParentPath) == "VC") { Path = ParentPath; IsVS2017OrNewer = false; return true; } } else { // This could be a new (>=VS2017) toolchain. If it is, we should find // path components with these prefixes when walking backwards through // the path. // Note: empty strings match anything. llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "", "MSVC", "Tools", "VC"}; auto It = llvm::sys::path::rbegin(PathEntry); auto End = llvm::sys::path::rend(PathEntry); for (llvm::StringRef Prefix : ExpectedPrefixes) { if (It == End) goto NotAToolChain; if (!It->startswith(Prefix)) goto NotAToolChain; ++It; } // We've found a new toolchain! // Back up 3 times (/bin/Host/arch) to get the root path. llvm::StringRef ToolChainPath(PathEntry); for (int i = 0; i < 3; ++i) ToolChainPath = llvm::sys::path::parent_path(ToolChainPath); Path = ToolChainPath; IsVS2017OrNewer = true; return true; } NotAToolChain: continue; } } return false; } // Query the Setup Config server for installs, then pick the newest version // and find its default VC toolchain. // This is the preferred way to discover new Visual Studios, as they're no // longer listed in the registry. static bool findVCToolChainViaSetupConfig(std::string &Path, bool &IsVS2017OrNewer) { #if !defined(USE_MSVC_SETUP_API) return false; #else // FIXME: This really should be done once in the top-level program's main // function, as it may have already been initialized with a different // threading model otherwise. llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded); HRESULT HR; // _com_ptr_t will throw a _com_error if a COM calls fail. // The LLVM coding standards forbid exception handling, so we'll have to // stop them from being thrown in the first place. // The destructor will put the regular error handler back when we leave // this scope. struct SuppressCOMErrorsRAII { static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {} SuppressCOMErrorsRAII() { _set_com_error_handler(handler); } ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); } } COMErrorSuppressor; ISetupConfigurationPtr Query; HR = Query.CreateInstance(__uuidof(SetupConfiguration)); if (FAILED(HR)) return false; IEnumSetupInstancesPtr EnumInstances; HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances); if (FAILED(HR)) return false; ISetupInstancePtr Instance; HR = EnumInstances->Next(1, &Instance, nullptr); if (HR != S_OK) return false; ISetupInstancePtr NewestInstance; Optional NewestVersionNum; do { bstr_t VersionString; uint64_t VersionNum; HR = Instance->GetInstallationVersion(VersionString.GetAddress()); if (FAILED(HR)) continue; HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum); if (FAILED(HR)) continue; if (!NewestVersionNum || (VersionNum > NewestVersionNum)) { NewestInstance = Instance; NewestVersionNum = VersionNum; } } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK); if (!NewestInstance) return false; bstr_t VCPathWide; HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress()); if (FAILED(HR)) return false; std::string VCRootPath; llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath); llvm::SmallString<256> ToolsVersionFilePath(VCRootPath); llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", "Microsoft.VCToolsVersion.default.txt"); auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath); if (!ToolsVersionFile) return false; llvm::SmallString<256> ToolchainPath(VCRootPath); llvm::sys::path::append(ToolchainPath, "Tools", "MSVC", ToolsVersionFile->get()->getBuffer().rtrim()); if (!llvm::sys::fs::is_directory(ToolchainPath)) return false; Path = ToolchainPath.str(); IsVS2017OrNewer = true; return true; #endif } // Look in the registry for Visual Studio installs, and use that to get // a toolchain path. VS2017 and newer don't get added to the registry. // So if we find something here, we know that it's an older version. static bool findVCToolChainViaRegistry(std::string &Path, bool &IsVS2017OrNewer) { std::string VSInstallPath; if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)", "InstallDir", VSInstallPath, nullptr) || getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)", "InstallDir", VSInstallPath, nullptr)) { if (!VSInstallPath.empty()) { llvm::SmallString<256> VCPath(llvm::StringRef( VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)"))); llvm::sys::path::append(VCPath, "VC"); Path = VCPath.str(); IsVS2017OrNewer = false; return true; } } return false; } // Try to find Exe from a Visual Studio distribution. This first tries to find // an installed copy of Visual Studio and, failing that, looks in the PATH, // making sure that whatever executable that's found is not a same-named exe // from clang itself to prevent clang from falling back to itself. static std::string FindVisualStudioExecutable(const ToolChain &TC, const char *Exe) { const auto &MSVC = static_cast(TC); SmallString<128> FilePath(MSVC.getSubDirectoryPath( toolchains::MSVCToolChain::SubDirectoryType::Bin)); llvm::sys::path::append(FilePath, Exe); return llvm::sys::fs::can_execute(FilePath) ? FilePath.str() : Exe; } void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; auto &TC = static_cast(getToolChain()); assert((Output.isFilename() || Output.isNothing()) && "invalid output"); if (Output.isFilename()) CmdArgs.push_back( Args.MakeArgString(std::string("-out:") + Output.getFilename())); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && !C.getDriver().IsCLMode()) CmdArgs.push_back("-defaultlib:libcmt"); if (!llvm::sys::Process::GetEnv("LIB")) { // If the VC environment hasn't been configured (perhaps because the user // did not run vcvarsall), try to build a consistent link environment. If // the environment variable is set however, assume the user knows what // they're doing. CmdArgs.push_back(Args.MakeArgString( Twine("-libpath:") + TC.getSubDirectoryPath( toolchains::MSVCToolChain::SubDirectoryType::Lib))); if (TC.useUniversalCRT()) { std::string UniversalCRTLibPath; if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) CmdArgs.push_back( Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath)); } std::string WindowsSdkLibPath; if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) CmdArgs.push_back( Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); } if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L)) for (const auto &LibPath : Args.getAllArgValues(options::OPT_L)) CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); CmdArgs.push_back("-nologo"); if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7, options::OPT__SLASH_Zd)) CmdArgs.push_back("-debug"); bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd, options::OPT_shared); if (DLL) { CmdArgs.push_back(Args.MakeArgString("-dll")); SmallString<128> ImplibName(Output.getFilename()); llvm::sys::path::replace_extension(ImplibName, "lib"); CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); } if (TC.getSanitizerArgs().needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); if (TC.getSanitizerArgs().needsSharedAsanRt() || Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); // Make sure the dynamic runtime thunk is not optimized out at link time // to ensure proper SEH handling. CmdArgs.push_back(Args.MakeArgString( TC.getArch() == llvm::Triple::x86 ? "-include:___asan_seh_interceptor" : "-include:__asan_seh_interceptor")); // Make sure the linker consider all object files from the dynamic runtime // thunk. CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk"))); } else if (DLL) { CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); } else { for (const auto &Lib : {"asan", "asan_cxx"}) { CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); // Make sure the linker consider all object files from the static lib. // This is necessary because instrumented dlls need access to all the // interface exported by the static lib in the main executable. CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + TC.getCompilerRT(Args, Lib))); } } } Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) { CmdArgs.push_back("-nodefaultlib:vcomp.lib"); CmdArgs.push_back("-nodefaultlib:vcompd.lib"); CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + TC.getDriver().Dir + "/../lib")); switch (TC.getDriver().getOpenMPRuntime(Args)) { case Driver::OMPRT_OMP: CmdArgs.push_back("-defaultlib:libomp.lib"); break; case Driver::OMPRT_IOMP5: CmdArgs.push_back("-defaultlib:libiomp5md.lib"); break; case Driver::OMPRT_GOMP: break; case Driver::OMPRT_Unknown: // Already diagnosed. break; } } // Add compiler-rt lib in case if it was explicitly // specified as an argument for --rtlib option. if (!Args.hasArg(options::OPT_nostdlib)) { AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); } // Add filenames, libraries, and other linker inputs. for (const auto &Input : Inputs) { if (Input.isFilename()) { CmdArgs.push_back(Input.getFilename()); continue; } const Arg &A = Input.getInputArg(); // Render -l options differently for the MSVC linker. if (A.getOption().matches(options::OPT_l)) { StringRef Lib = A.getValue(); const char *LinkLibArg; if (Lib.endswith(".lib")) LinkLibArg = Args.MakeArgString(Lib); else LinkLibArg = Args.MakeArgString(Lib + ".lib"); CmdArgs.push_back(LinkLibArg); continue; } // Otherwise, this is some other kind of linker input option like -Wl, -z, // or -L. Render it, even if MSVC doesn't understand it. A.renderAsInput(Args, CmdArgs); } TC.addProfileRTLibs(Args, CmdArgs); std::vector Environment; // We need to special case some linker paths. In the case of lld, we need to // translate 'lld' into 'lld-link', and in the case of the regular msvc // linker, we need to use a special search algorithm. llvm::SmallString<128> linkPath; StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link"); if (Linker.equals_lower("lld")) Linker = "lld-link"; if (Linker.equals_lower("link")) { // If we're using the MSVC linker, it's not sufficient to just use link // from the program PATH, because other environments like GnuWin32 install // their own link.exe which may come first. linkPath = FindVisualStudioExecutable(TC, "link.exe"); #ifdef USE_WIN32 // When cross-compiling with VS2017 or newer, link.exe expects to have // its containing bin directory at the top of PATH, followed by the // native target bin directory. // e.g. when compiling for x86 on an x64 host, PATH should start with: // /bin/HostX64/x86;/bin/HostX64/x64 if (TC.getIsVS2017OrNewer() && llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) { auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch(); auto EnvBlockWide = std::unique_ptr( GetEnvironmentStringsW(), FreeEnvironmentStringsW); if (!EnvBlockWide) goto SkipSettingEnvironment; size_t EnvCount = 0; size_t EnvBlockLen = 0; while (EnvBlockWide[EnvBlockLen] != L'\0') { ++EnvCount; EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) + 1 /*string null-terminator*/; } ++EnvBlockLen; // add the block null-terminator std::string EnvBlock; if (!llvm::convertUTF16ToUTF8String( llvm::ArrayRef(reinterpret_cast(EnvBlockWide.get()), EnvBlockLen * sizeof(EnvBlockWide[0])), EnvBlock)) goto SkipSettingEnvironment; Environment.reserve(EnvCount); // Now loop over each string in the block and copy them into the // environment vector, adjusting the PATH variable as needed when we // find it. for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) { llvm::StringRef EnvVar(Cursor); if (EnvVar.startswith_lower("path=")) { using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType; constexpr size_t PrefixLen = 5; // strlen("path=") Environment.push_back(Args.MakeArgString( EnvVar.substr(0, PrefixLen) + TC.getSubDirectoryPath(SubDirectoryType::Bin) + llvm::Twine(llvm::sys::EnvPathSeparator) + TC.getSubDirectoryPath(SubDirectoryType::Bin, HostArch) + (EnvVar.size() > PrefixLen ? llvm::Twine(llvm::sys::EnvPathSeparator) + EnvVar.substr(PrefixLen) : ""))); } else { Environment.push_back(Args.MakeArgString(EnvVar)); } Cursor += EnvVar.size() + 1 /*null-terminator*/; } } SkipSettingEnvironment:; #endif } else { linkPath = Linker; llvm::sys::path::replace_extension(linkPath, "exe"); linkPath = TC.GetProgramPath(linkPath.c_str()); } auto LinkCmd = llvm::make_unique( JA, *this, Args.MakeArgString(linkPath), CmdArgs, Inputs); if (!Environment.empty()) LinkCmd->setEnvironment(Environment); C.addCommand(std::move(LinkCmd)); } void visualstudio::Compiler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput)); } std::unique_ptr visualstudio::Compiler::GetCommand( Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("/nologo"); CmdArgs.push_back("/c"); // Compile only. CmdArgs.push_back("/W0"); // No warnings. // The goal is to be able to invoke this tool correctly based on // any flag accepted by clang-cl. // These are spelled the same way in clang and cl.exe,. Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I}); // Optimization level. if (Arg *A = Args.getLastArg(options::OPT_fbuiltin, options::OPT_fno_builtin)) CmdArgs.push_back(A->getOption().getID() == options::OPT_fbuiltin ? "/Oi" : "/Oi-"); if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) { if (A->getOption().getID() == options::OPT_O0) { CmdArgs.push_back("/Od"); } else { CmdArgs.push_back("/Og"); StringRef OptLevel = A->getValue(); if (OptLevel == "s" || OptLevel == "z") CmdArgs.push_back("/Os"); else CmdArgs.push_back("/Ot"); CmdArgs.push_back("/Ob2"); } } if (Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, options::OPT_fno_omit_frame_pointer)) CmdArgs.push_back(A->getOption().getID() == options::OPT_fomit_frame_pointer ? "/Oy" : "/Oy-"); if (!Args.hasArg(options::OPT_fwritable_strings)) CmdArgs.push_back("/GF"); // Flags for which clang-cl has an alias. // FIXME: How can we ensure this stays in sync with relevant clang-cl options? if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, /*default=*/false)) CmdArgs.push_back("/GR-"); if (Args.hasFlag(options::OPT__SLASH_GS_, options::OPT__SLASH_GS, /*default=*/false)) CmdArgs.push_back("/GS-"); if (Arg *A = Args.getLastArg(options::OPT_ffunction_sections, options::OPT_fno_function_sections)) CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections ? "/Gy" : "/Gy-"); if (Arg *A = Args.getLastArg(options::OPT_fdata_sections, options::OPT_fno_data_sections)) CmdArgs.push_back( A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-"); if (Args.hasArg(options::OPT_fsyntax_only)) CmdArgs.push_back("/Zs"); if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only, options::OPT__SLASH_Z7)) CmdArgs.push_back("/Z7"); std::vector Includes = Args.getAllArgValues(options::OPT_include); for (const auto &Include : Includes) CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include)); // Flags that can simply be passed through. Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX_); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_Zl); // The order of these flags is relevant, so pick the last one. if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd, options::OPT__SLASH_MT, options::OPT__SLASH_MTd)) A->render(Args, CmdArgs); // Use MSVC's default threadsafe statics behaviour unless there was a flag. if (Arg *A = Args.getLastArg(options::OPT_fthreadsafe_statics, options::OPT_fno_threadsafe_statics)) { CmdArgs.push_back(A->getOption().getID() == options::OPT_fthreadsafe_statics ? "/Zc:threadSafeInit" : "/Zc:threadSafeInit-"); } // Pass through all unknown arguments so that the fallback command can see // them too. Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN); // Input filename. assert(Inputs.size() == 1); const InputInfo &II = Inputs[0]; assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX); CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp"); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); // Output filename. assert(Output.getType() == types::TY_Object); const char *Fo = Args.MakeArgString(std::string("/Fo") + Output.getFilename()); CmdArgs.push_back(Fo); std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe"); return llvm::make_unique(JA, *this, Args.MakeArgString(Exec), CmdArgs, Inputs); } MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); // Check the environment first, since that's probably the user telling us // what they want to use. // Failing that, just try to find the newest Visual Studio version we can // and use its default VC toolchain. findVCToolChainViaEnvironment(VCToolChainPath, IsVS2017OrNewer) || findVCToolChainViaSetupConfig(VCToolChainPath, IsVS2017OrNewer) || findVCToolChainViaRegistry(VCToolChainPath, IsVS2017OrNewer); } Tool *MSVCToolChain::buildLinker() const { if (VCToolChainPath.empty()) getDriver().Diag(clang::diag::warn_drv_msvc_not_found); return new tools::visualstudio::Linker(*this); } Tool *MSVCToolChain::buildAssembler() const { if (getTriple().isOSBinFormatMachO()) return new tools::darwin::Assembler(*this); getDriver().Diag(clang::diag::err_no_external_assembler); return nullptr; } bool MSVCToolChain::IsIntegratedAssemblerDefault() const { return true; } bool MSVCToolChain::IsUnwindTablesDefault() const { // Emit unwind tables by default on Win64. All non-x86_32 Windows platforms // such as ARM and PPC actually require unwind tables, but LLVM doesn't know // how to generate them yet. // Don't emit unwind tables by default for MachO targets. if (getTriple().isOSBinFormatMachO()) return false; return getArch() == llvm::Triple::x86_64; } bool MSVCToolChain::isPICDefault() const { return getArch() == llvm::Triple::x86_64; } bool MSVCToolChain::isPIEDefault() const { return false; } bool MSVCToolChain::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { CudaInstallation.print(OS); } // Windows SDKs and VC Toolchains group their contents into subdirectories based // on the target architecture. This function converts an llvm::Triple::ArchType // to the corresponding subdirectory name. static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { using ArchType = llvm::Triple::ArchType; switch (Arch) { case ArchType::x86: return "x86"; case ArchType::x86_64: return "x64"; case ArchType::arm: return "arm"; default: return ""; } } // Similar to the above function, but for Visual Studios before VS2017. static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { using ArchType = llvm::Triple::ArchType; switch (Arch) { case ArchType::x86: // x86 is default in legacy VC toolchains. // e.g. x86 libs are directly in /lib as opposed to /lib/x86. return ""; case ArchType::x86_64: return "amd64"; case ArchType::arm: return "arm"; default: return ""; } } // Get the path to a specific subdirectory in the current toolchain for // a given target architecture. // VS2017 changed the VC toolchain layout, so this should be used instead // of hardcoding paths. std::string MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type, llvm::Triple::ArchType TargetArch) const { llvm::SmallString<256> Path(VCToolChainPath); switch (Type) { case SubDirectoryType::Bin: if (IsVS2017OrNewer) { bool HostIsX64 = llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit(); llvm::sys::path::append(Path, "bin", (HostIsX64 ? "HostX64" : "HostX86"), llvmArchToWindowsSDKArch(TargetArch)); } else { llvm::sys::path::append(Path, "bin", llvmArchToLegacyVCArch(TargetArch)); } break; case SubDirectoryType::Include: llvm::sys::path::append(Path, "include"); break; case SubDirectoryType::Lib: llvm::sys::path::append( Path, "lib", IsVS2017OrNewer ? llvmArchToWindowsSDKArch(TargetArch) : llvmArchToLegacyVCArch(TargetArch)); break; } return Path.str(); } #ifdef USE_WIN32 static bool readFullStringValue(HKEY hkey, const char *valueName, std::string &value) { std::wstring WideValueName; if (!llvm::ConvertUTF8toWide(valueName, WideValueName)) return false; DWORD result = 0; DWORD valueSize = 0; DWORD type = 0; // First just query for the required size. result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL, &valueSize); if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize) return false; std::vector buffer(valueSize); result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0], &valueSize); if (result == ERROR_SUCCESS) { std::wstring WideValue(reinterpret_cast(buffer.data()), valueSize / sizeof(wchar_t)); if (valueSize && WideValue.back() == L'\0') { WideValue.pop_back(); } // The destination buffer must be empty as an invariant of the conversion // function; but this function is sometimes called in a loop that passes in // the same buffer, however. Simply clear it out so we can overwrite it. value.clear(); return llvm::convertWideToUTF8(WideValue, value); } return false; } #endif /// \brief Read registry string. /// This also supports a means to look for high-versioned keys by use /// of a $VERSION placeholder in the key path. /// $VERSION in the key path is a placeholder for the version number, /// causing the highest value path to be searched for and used. /// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". /// There can be additional characters in the component. Only the numeric /// characters are compared. This function only searches HKLM. static bool getSystemRegistryString(const char *keyPath, const char *valueName, std::string &value, std::string *phValue) { #ifndef USE_WIN32 return false; #else HKEY hRootKey = HKEY_LOCAL_MACHINE; HKEY hKey = NULL; long lResult; bool returnValue = false; const char *placeHolder = strstr(keyPath, "$VERSION"); std::string bestName; // If we have a $VERSION placeholder, do the highest-version search. if (placeHolder) { const char *keyEnd = placeHolder - 1; const char *nextKey = placeHolder; // Find end of previous key. while ((keyEnd > keyPath) && (*keyEnd != '\\')) keyEnd--; // Find end of key containing $VERSION. while (*nextKey && (*nextKey != '\\')) nextKey++; size_t partialKeyLength = keyEnd - keyPath; char partialKey[256]; if (partialKeyLength >= sizeof(partialKey)) partialKeyLength = sizeof(partialKey) - 1; strncpy(partialKey, keyPath, partialKeyLength); partialKey[partialKeyLength] = '\0'; HKEY hTopKey = NULL; lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY, &hTopKey); if (lResult == ERROR_SUCCESS) { char keyName[256]; double bestValue = 0.0; DWORD index, size = sizeof(keyName) - 1; for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; index++) { const char *sp = keyName; while (*sp && !isDigit(*sp)) sp++; if (!*sp) continue; const char *ep = sp + 1; while (*ep && (isDigit(*ep) || (*ep == '.'))) ep++; char numBuf[32]; strncpy(numBuf, sp, sizeof(numBuf) - 1); numBuf[sizeof(numBuf) - 1] = '\0'; double dvalue = strtod(numBuf, NULL); if (dvalue > bestValue) { // Test that InstallDir is indeed there before keeping this index. // Open the chosen key path remainder. bestName = keyName; // Append rest of key. bestName.append(nextKey); lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0, KEY_READ | KEY_WOW64_32KEY, &hKey); if (lResult == ERROR_SUCCESS) { if (readFullStringValue(hKey, valueName, value)) { bestValue = dvalue; if (phValue) *phValue = bestName; returnValue = true; } RegCloseKey(hKey); } } size = sizeof(keyName) - 1; } RegCloseKey(hTopKey); } } else { lResult = RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); if (lResult == ERROR_SUCCESS) { if (readFullStringValue(hKey, valueName, value)) returnValue = true; if (phValue) phValue->clear(); RegCloseKey(hKey); } } return returnValue; #endif // USE_WIN32 } // Find the most recent version of Universal CRT or Windows 10 SDK. // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include // directory by name and uses the last one of the list. // So we compare entry names lexicographically to find the greatest one. static bool getWindows10SDKVersionFromPath(const std::string &SDKPath, std::string &SDKVersion) { SDKVersion.clear(); std::error_code EC; llvm::SmallString<128> IncludePath(SDKPath); llvm::sys::path::append(IncludePath, "Include"); for (llvm::sys::fs::directory_iterator DirIt(IncludePath, EC), DirEnd; DirIt != DirEnd && !EC; DirIt.increment(EC)) { if (!llvm::sys::fs::is_directory(DirIt->path())) continue; StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); // If WDK is installed, there could be subfolders like "wdf" in the // "Include" directory. // Allow only directories which names start with "10.". if (!CandidateName.startswith("10.")) continue; if (CandidateName > SDKVersion) SDKVersion = CandidateName; } return !SDKVersion.empty(); } /// \brief Get Windows SDK installation directory. static bool getWindowsSDKDir(std::string &Path, int &Major, std::string &WindowsSDKIncludeVersion, std::string &WindowsSDKLibVersion) { std::string RegistrySDKVersion; // Try the Windows registry. if (!getSystemRegistryString( "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", "InstallationFolder", Path, &RegistrySDKVersion)) return false; if (Path.empty() || RegistrySDKVersion.empty()) return false; WindowsSDKIncludeVersion.clear(); WindowsSDKLibVersion.clear(); Major = 0; std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); if (Major <= 7) return true; if (Major == 8) { // Windows SDK 8.x installs libraries in a folder whose names depend on the // version of the OS you're targeting. By default choose the newest, which // usually corresponds to the version of the OS you've installed the SDK on. const char *Tests[] = {"winv6.3", "win8", "win7"}; for (const char *Test : Tests) { llvm::SmallString<128> TestPath(Path); llvm::sys::path::append(TestPath, "Lib", Test); if (llvm::sys::fs::exists(TestPath.c_str())) { WindowsSDKLibVersion = Test; break; } } return !WindowsSDKLibVersion.empty(); } if (Major == 10) { if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion)) return false; WindowsSDKLibVersion = WindowsSDKIncludeVersion; return true; } // Unsupported SDK version return false; } // Gets the library path required to link against the Windows SDK. bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const { std::string sdkPath; int sdkMajor = 0; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; path.clear(); if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion, windowsSDKLibVersion)) return false; llvm::SmallString<128> libPath(sdkPath); llvm::sys::path::append(libPath, "Lib"); if (sdkMajor >= 8) { llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", llvmArchToWindowsSDKArch(getArch())); } else { switch (getArch()) { // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. case llvm::Triple::x86: break; case llvm::Triple::x86_64: llvm::sys::path::append(libPath, "x64"); break; case llvm::Triple::arm: // It is not necessary to link against Windows SDK 7.x when targeting ARM. return false; default: return false; } } path = libPath.str(); return true; } // Check if the Include path of a specified version of Visual Studio contains // specific header files. If not, they are probably shipped with Universal CRT. bool MSVCToolChain::useUniversalCRT() const { llvm::SmallString<128> TestPath( getSubDirectoryPath(SubDirectoryType::Include)); llvm::sys::path::append(TestPath, "stdlib.h"); return !llvm::sys::fs::exists(TestPath); } static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) { // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry // for the specific key "KitsRoot10". So do we. if (!getSystemRegistryString( "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", Path, nullptr)) return false; return getWindows10SDKVersionFromPath(Path, UCRTVersion); } bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const { std::string UniversalCRTSdkPath; std::string UCRTVersion; Path.clear(); if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) return false; StringRef ArchName = llvmArchToWindowsSDKArch(getArch()); if (ArchName.empty()) return false; llvm::SmallString<128> LibPath(UniversalCRTSdkPath); llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); Path = LibPath.str(); return true; } static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) { unsigned Major, Minor, Micro; Triple.getEnvironmentVersion(Major, Minor, Micro); if (Major || Minor || Micro) return VersionTuple(Major, Minor, Micro); return VersionTuple(); } static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) { VersionTuple Version; #ifdef USE_WIN32 SmallString<128> ClExe(BinDir); llvm::sys::path::append(ClExe, "cl.exe"); std::wstring ClExeWide; if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide)) return Version; const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(), nullptr); if (VersionSize == 0) return Version; SmallVector VersionBlock(VersionSize); if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize, VersionBlock.data())) return Version; VS_FIXEDFILEINFO *FileInfo = nullptr; UINT FileInfoSize = 0; if (!::VerQueryValueW(VersionBlock.data(), L"\\", reinterpret_cast(&FileInfo), &FileInfoSize) || FileInfoSize < sizeof(*FileInfo)) return Version; const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF; const unsigned Minor = (FileInfo->dwFileVersionMS ) & 0xFFFF; const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF; Version = VersionTuple(Major, Minor, Micro); #endif return Version; } void MSVCToolChain::AddSystemIncludeWithSubfolder( const ArgList &DriverArgs, ArgStringList &CC1Args, const std::string &folder, const Twine &subfolder1, const Twine &subfolder2, const Twine &subfolder3) const { llvm::SmallString<128> path(folder); llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3); addSystemInclude(DriverArgs, CC1Args, path); } void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc)) return; if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir, "include"); } // Add %INCLUDE%-like directories from the -imsvc flag. for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc)) addSystemInclude(DriverArgs, CC1Args, Path); if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat. if (llvm::Optional cl_include_dir = llvm::sys::Process::GetEnv("INCLUDE")) { SmallVector Dirs; StringRef(*cl_include_dir) .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false); for (StringRef Dir : Dirs) addSystemInclude(DriverArgs, CC1Args, Dir); if (!Dirs.empty()) return; } // When built with access to the proper Windows APIs, try to actually find // the correct include paths first. if (!VCToolChainPath.empty()) { addSystemInclude(DriverArgs, CC1Args, getSubDirectoryPath(SubDirectoryType::Include)); if (useUniversalCRT()) { std::string UniversalCRTSdkPath; std::string UCRTVersion; if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, "Include", UCRTVersion, "ucrt"); } } std::string WindowsSDKDir; int major; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; if (getWindowsSDKDir(WindowsSDKDir, major, windowsSDKIncludeVersion, windowsSDKLibVersion)) { if (major >= 8) { // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. // Anyway, llvm::sys::path::append is able to manage it. AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "include", windowsSDKIncludeVersion, "shared"); AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "include", windowsSDKIncludeVersion, "um"); AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "include", windowsSDKIncludeVersion, "winrt"); } else { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "include"); } } return; } #if defined(LLVM_ON_WIN32) // As a fallback, select default install paths. // FIXME: Don't guess drives and paths like this on Windows. const StringRef Paths[] = { "C:/Program Files/Microsoft Visual Studio 10.0/VC/include", "C:/Program Files/Microsoft Visual Studio 9.0/VC/include", "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", "C:/Program Files/Microsoft Visual Studio 8/VC/include", "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include" }; addSystemIncludes(DriverArgs, CC1Args, Paths); #endif } void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { // FIXME: There should probably be logic here to find libc++ on Windows. } VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, const ArgList &Args) const { bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment(); VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args); if (MSVT.empty()) MSVT = getMSVCVersionFromTriple(getTriple()); if (MSVT.empty() && IsWindowsMSVC) MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin)); if (MSVT.empty() && Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) { // -fms-compatibility-version=18.00 is default. // FIXME: Consider bumping this to 19 (MSVC2015) soon. MSVT = VersionTuple(18); } return MSVT; } std::string MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { // The MSVC version doesn't care about the architecture, even though it // may look at the triple internally. VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args); MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0), MSVT.getSubminor().getValueOr(0)); // For the rest of the triple, however, a computed architecture name may // be needed. llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType)); if (Triple.getEnvironment() == llvm::Triple::MSVC) { StringRef ObjFmt = Triple.getEnvironmentName().split('-').second; if (ObjFmt.empty()) Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str()); else Triple.setEnvironmentName( (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str()); } return Triple.getTriple(); } SanitizerMask MSVCToolChain::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; return Res; } static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, bool SupportsForcingFramePointer, const char *ExpandChar, const OptTable &Opts) { assert(A->getOption().matches(options::OPT__SLASH_O)); StringRef OptStr = A->getValue(); for (size_t I = 0, E = OptStr.size(); I != E; ++I) { const char &OptChar = *(OptStr.data() + I); switch (OptChar) { default: break; case '1': case '2': case 'x': case 'd': if (&OptChar == ExpandChar) { if (OptChar == 'd') { DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); } else { if (OptChar == '1') { DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); } else if (OptChar == '2' || OptChar == 'x') { DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); } if (SupportsForcingFramePointer && !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); if (OptChar == '1' || OptChar == '2') DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); } } break; case 'b': if (I + 1 != E && isdigit(OptStr[I + 1])) { switch (OptStr[I + 1]) { case '0': DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); break; case '1': DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions)); break; case '2': DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); break; } ++I; } break; case 'g': break; case 'i': if (I + 1 != E && OptStr[I + 1] == '-') { ++I; DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); } else { DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); } break; case 's': DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); break; case 't': DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); break; case 'y': { bool OmitFramePointer = true; if (I + 1 != E && OptStr[I + 1] == '-') { OmitFramePointer = false; ++I; } if (SupportsForcingFramePointer) { if (OmitFramePointer) DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); else DAL.AddFlagArg( A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); } else { // Don't warn about /Oy- in 64-bit builds (where // SupportsForcingFramePointer is false). The flag having no effect // there is a compiler-internal optimization, and people shouldn't have // to special-case their build files for 64-bit clang-cl. A->claim(); } break; } } } } static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL, const OptTable &Opts) { assert(A->getOption().matches(options::OPT_D)); StringRef Val = A->getValue(); size_t Hash = Val.find('#'); if (Hash == StringRef::npos || Hash > Val.find('=')) { DAL.append(A); return; } std::string NewVal = Val; NewVal[Hash] = '='; DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal); } llvm::opt::DerivedArgList * MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); // /Oy and /Oy- only has an effect under X86-32. bool SupportsForcingFramePointer = getArch() == llvm::Triple::x86; // The -O[12xd] flag actually expands to several flags. We must desugar the // flags so that options embedded can be negated. For example, the '-O2' flag // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single // aspect of '-O2'. // // Note that this expansion logic only applies to the *last* of '[12xd]'. // First step is to search for the character we'd like to expand. const char *ExpandChar = nullptr; for (Arg *A : Args) { if (!A->getOption().matches(options::OPT__SLASH_O)) continue; StringRef OptStr = A->getValue(); for (size_t I = 0, E = OptStr.size(); I != E; ++I) { char OptChar = OptStr[I]; char PrevChar = I > 0 ? OptStr[I - 1] : '0'; if (PrevChar == 'b') { // OptChar does not expand; it's an argument to the previous char. continue; } if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd') ExpandChar = OptStr.data() + I; } } for (Arg *A : Args) { if (A->getOption().matches(options::OPT__SLASH_O)) { // The -O flag actually takes an amalgam of other options. For example, // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'. TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts); } else if (A->getOption().matches(options::OPT_D)) { // Translate -Dfoo#bar into -Dfoo=bar. TranslateDArg(A, *DAL, Opts); } else { DAL->append(A); } } return DAL; } Index: vendor/clang/dist/lib/Frontend/ASTUnit.cpp =================================================================== --- vendor/clang/dist/lib/Frontend/ASTUnit.cpp (revision 318415) +++ vendor/clang/dist/lib/Frontend/ASTUnit.cpp (revision 318416) @@ -1,2890 +1,2867 @@ //===--- ASTUnit.cpp - ASTUnit utility --------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // ASTUnit Implementation. // //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTUnit.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/MemoryBufferCache.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/Sema.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include #include #include using namespace clang; using llvm::TimeRecord; namespace { class SimpleTimer { bool WantTiming; TimeRecord Start; std::string Output; public: explicit SimpleTimer(bool WantTiming) : WantTiming(WantTiming) { if (WantTiming) Start = TimeRecord::getCurrentTime(); } void setOutput(const Twine &Output) { if (WantTiming) this->Output = Output.str(); } ~SimpleTimer() { if (WantTiming) { TimeRecord Elapsed = TimeRecord::getCurrentTime(); Elapsed -= Start; llvm::errs() << Output << ':'; Elapsed.print(Elapsed, llvm::errs()); llvm::errs() << '\n'; } } }; struct OnDiskData { /// \brief The file in which the precompiled preamble is stored. std::string PreambleFile; - /// \brief Temporary files that should be removed when the ASTUnit is - /// destroyed. - SmallVector TemporaryFiles; - - /// \brief Erase temporary files. - void CleanTemporaryFiles(); - /// \brief Erase the preamble file. void CleanPreambleFile(); /// \brief Erase temporary files and the preamble file. void Cleanup(); }; } static llvm::sys::SmartMutex &getOnDiskMutex() { static llvm::sys::SmartMutex M(/* recursive = */ true); return M; } static void cleanupOnDiskMapAtExit(); typedef llvm::DenseMap> OnDiskDataMap; static OnDiskDataMap &getOnDiskDataMap() { static OnDiskDataMap M; static bool hasRegisteredAtExit = false; if (!hasRegisteredAtExit) { hasRegisteredAtExit = true; atexit(cleanupOnDiskMapAtExit); } return M; } static void cleanupOnDiskMapAtExit() { // Use the mutex because there can be an alive thread destroying an ASTUnit. llvm::MutexGuard Guard(getOnDiskMutex()); for (const auto &I : getOnDiskDataMap()) { // We don't worry about freeing the memory associated with OnDiskDataMap. // All we care about is erasing stale files. I.second->Cleanup(); } } static OnDiskData &getOnDiskData(const ASTUnit *AU) { // We require the mutex since we are modifying the structure of the // DenseMap. llvm::MutexGuard Guard(getOnDiskMutex()); OnDiskDataMap &M = getOnDiskDataMap(); auto &D = M[AU]; if (!D) D = llvm::make_unique(); return *D; } static void erasePreambleFile(const ASTUnit *AU) { getOnDiskData(AU).CleanPreambleFile(); } static void removeOnDiskEntry(const ASTUnit *AU) { // We require the mutex since we are modifying the structure of the // DenseMap. llvm::MutexGuard Guard(getOnDiskMutex()); OnDiskDataMap &M = getOnDiskDataMap(); OnDiskDataMap::iterator I = M.find(AU); if (I != M.end()) { I->second->Cleanup(); M.erase(I); } } static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) { getOnDiskData(AU).PreambleFile = preambleFile; } static const std::string &getPreambleFile(const ASTUnit *AU) { return getOnDiskData(AU).PreambleFile; } -void OnDiskData::CleanTemporaryFiles() { - for (StringRef File : TemporaryFiles) - llvm::sys::fs::remove(File); - TemporaryFiles.clear(); -} - void OnDiskData::CleanPreambleFile() { if (!PreambleFile.empty()) { llvm::sys::fs::remove(PreambleFile); PreambleFile.clear(); } } void OnDiskData::Cleanup() { - CleanTemporaryFiles(); CleanPreambleFile(); } struct ASTUnit::ASTWriterData { SmallString<128> Buffer; llvm::BitstreamWriter Stream; ASTWriter Writer; ASTWriterData(MemoryBufferCache &PCMCache) : Stream(Buffer), Writer(Stream, Buffer, PCMCache, {}) {} }; void ASTUnit::clearFileLevelDecls() { llvm::DeleteContainerSeconds(FileDecls); } -void ASTUnit::CleanTemporaryFiles() { - getOnDiskData(this).CleanTemporaryFiles(); -} - -void ASTUnit::addTemporaryFile(StringRef TempFile) { - getOnDiskData(this).TemporaryFiles.push_back(TempFile); -} - /// \brief After failing to build a precompiled preamble (due to /// errors in the source that occurs in the preamble), the number of /// reparses during which we'll skip even trying to precompile the /// preamble. const unsigned DefaultPreambleRebuildInterval = 5; /// \brief Tracks the number of ASTUnit objects that are currently active. /// /// Used for debugging purposes only. static std::atomic ActiveASTUnitObjects; ASTUnit::ASTUnit(bool _MainFileIsAST) : Reader(nullptr), HadModuleLoaderFatalFailure(false), OnlyLocalDecls(false), CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")), OwnsRemappedFileBuffers(true), NumStoredDiagnosticsFromDriver(0), PreambleRebuildCounter(0), NumWarningsInPreamble(0), ShouldCacheCodeCompletionResults(false), IncludeBriefCommentsInCodeCompletion(false), UserFilesAreVolatile(false), CompletionCacheTopLevelHashValue(0), PreambleTopLevelHashValue(0), CurrentTopLevelHashValue(0), UnsafeToFree(false) { if (getenv("LIBCLANG_OBJTRACKING")) fprintf(stderr, "+++ %u translation units\n", ++ActiveASTUnitObjects); } ASTUnit::~ASTUnit() { // If we loaded from an AST file, balance out the BeginSourceFile call. if (MainFileIsAST && getDiagnostics().getClient()) { getDiagnostics().getClient()->EndSourceFile(); } clearFileLevelDecls(); // Clean up the temporary files and the preamble file. removeOnDiskEntry(this); // Free the buffers associated with remapped files. We are required to // perform this operation here because we explicitly request that the // compiler instance *not* free these buffers for each invocation of the // parser. if (Invocation && OwnsRemappedFileBuffers) { PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); for (const auto &RB : PPOpts.RemappedFileBuffers) delete RB.second; } ClearCachedCompletionResults(); if (getenv("LIBCLANG_OBJTRACKING")) fprintf(stderr, "--- %u translation units\n", --ActiveASTUnitObjects); } void ASTUnit::setPreprocessor(std::shared_ptr PP) { this->PP = std::move(PP); } /// \brief Determine the set of code-completion contexts in which this /// declaration should be shown. static unsigned getDeclShowContexts(const NamedDecl *ND, const LangOptions &LangOpts, bool &IsNestedNameSpecifier) { IsNestedNameSpecifier = false; if (isa(ND)) ND = dyn_cast(ND->getUnderlyingDecl()); if (!ND) return 0; uint64_t Contexts = 0; if (isa(ND) || isa(ND) || isa(ND) || isa(ND)) { // Types can appear in these contexts. if (LangOpts.CPlusPlus || !isa(ND)) Contexts |= (1LL << CodeCompletionContext::CCC_TopLevel) | (1LL << CodeCompletionContext::CCC_ObjCIvarList) | (1LL << CodeCompletionContext::CCC_ClassStructUnion) | (1LL << CodeCompletionContext::CCC_Statement) | (1LL << CodeCompletionContext::CCC_Type) | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression); // In C++, types can appear in expressions contexts (for functional casts). if (LangOpts.CPlusPlus) Contexts |= (1LL << CodeCompletionContext::CCC_Expression); // In Objective-C, message sends can send interfaces. In Objective-C++, // all types are available due to functional casts. if (LangOpts.CPlusPlus || isa(ND)) Contexts |= (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver); // In Objective-C, you can only be a subclass of another Objective-C class if (isa(ND)) Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName); // Deal with tag names. if (isa(ND)) { Contexts |= (1LL << CodeCompletionContext::CCC_EnumTag); // Part of the nested-name-specifier in C++0x. if (LangOpts.CPlusPlus11) IsNestedNameSpecifier = true; } else if (const RecordDecl *Record = dyn_cast(ND)) { if (Record->isUnion()) Contexts |= (1LL << CodeCompletionContext::CCC_UnionTag); else Contexts |= (1LL << CodeCompletionContext::CCC_ClassOrStructTag); if (LangOpts.CPlusPlus) IsNestedNameSpecifier = true; } else if (isa(ND)) IsNestedNameSpecifier = true; } else if (isa(ND) || isa(ND)) { // Values can appear in these contexts. Contexts = (1LL << CodeCompletionContext::CCC_Statement) | (1LL << CodeCompletionContext::CCC_Expression) | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver); } else if (isa(ND)) { Contexts = (1LL << CodeCompletionContext::CCC_ObjCProtocolName); } else if (isa(ND)) { Contexts = (1LL << CodeCompletionContext::CCC_ObjCCategoryName); } else if (isa(ND) || isa(ND)) { Contexts = (1LL << CodeCompletionContext::CCC_Namespace); // Part of the nested-name-specifier. IsNestedNameSpecifier = true; } return Contexts; } void ASTUnit::CacheCodeCompletionResults() { if (!TheSema) return; SimpleTimer Timer(WantTiming); Timer.setOutput("Cache global code completions for " + getMainFileName()); // Clear out the previous results. ClearCachedCompletionResults(); // Gather the set of global code completions. typedef CodeCompletionResult Result; SmallVector Results; CachedCompletionAllocator = std::make_shared(); CodeCompletionTUInfo CCTUInfo(CachedCompletionAllocator); TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, CCTUInfo, Results); // Translate global code completions into cached completions. llvm::DenseMap CompletionTypes; CodeCompletionContext CCContext(CodeCompletionContext::CCC_TopLevel); for (Result &R : Results) { switch (R.Kind) { case Result::RK_Declaration: { bool IsNestedNameSpecifier = false; CachedCodeCompletionResult CachedResult; CachedResult.Completion = R.CreateCodeCompletionString( *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = getDeclShowContexts( R.Declaration, Ctx->getLangOpts(), IsNestedNameSpecifier); CachedResult.Priority = R.Priority; CachedResult.Kind = R.CursorKind; CachedResult.Availability = R.Availability; // Keep track of the type of this completion in an ASTContext-agnostic // way. QualType UsageType = getDeclUsageType(*Ctx, R.Declaration); if (UsageType.isNull()) { CachedResult.TypeClass = STC_Void; CachedResult.Type = 0; } else { CanQualType CanUsageType = Ctx->getCanonicalType(UsageType.getUnqualifiedType()); CachedResult.TypeClass = getSimplifiedTypeClass(CanUsageType); // Determine whether we have already seen this type. If so, we save // ourselves the work of formatting the type string by using the // temporary, CanQualType-based hash table to find the associated value. unsigned &TypeValue = CompletionTypes[CanUsageType]; if (TypeValue == 0) { TypeValue = CompletionTypes.size(); CachedCompletionTypes[QualType(CanUsageType).getAsString()] = TypeValue; } CachedResult.Type = TypeValue; } CachedCompletionResults.push_back(CachedResult); /// Handle nested-name-specifiers in C++. if (TheSema->Context.getLangOpts().CPlusPlus && IsNestedNameSpecifier && !R.StartsNestedNameSpecifier) { // The contexts in which a nested-name-specifier can appear in C++. uint64_t NNSContexts = (1LL << CodeCompletionContext::CCC_TopLevel) | (1LL << CodeCompletionContext::CCC_ObjCIvarList) | (1LL << CodeCompletionContext::CCC_ClassStructUnion) | (1LL << CodeCompletionContext::CCC_Statement) | (1LL << CodeCompletionContext::CCC_Expression) | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) | (1LL << CodeCompletionContext::CCC_EnumTag) | (1LL << CodeCompletionContext::CCC_UnionTag) | (1LL << CodeCompletionContext::CCC_ClassOrStructTag) | (1LL << CodeCompletionContext::CCC_Type) | (1LL << CodeCompletionContext::CCC_PotentiallyQualifiedName) | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression); if (isa(R.Declaration) || isa(R.Declaration)) NNSContexts |= (1LL << CodeCompletionContext::CCC_Namespace); if (unsigned RemainingContexts = NNSContexts & ~CachedResult.ShowInContexts) { // If there any contexts where this completion can be a // nested-name-specifier but isn't already an option, create a // nested-name-specifier completion. R.StartsNestedNameSpecifier = true; CachedResult.Completion = R.CreateCodeCompletionString( *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = RemainingContexts; CachedResult.Priority = CCP_NestedNameSpecifier; CachedResult.TypeClass = STC_Void; CachedResult.Type = 0; CachedCompletionResults.push_back(CachedResult); } } break; } case Result::RK_Keyword: case Result::RK_Pattern: // Ignore keywords and patterns; we don't care, since they are so // easily regenerated. break; case Result::RK_Macro: { CachedCodeCompletionResult CachedResult; CachedResult.Completion = R.CreateCodeCompletionString( *TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = (1LL << CodeCompletionContext::CCC_TopLevel) | (1LL << CodeCompletionContext::CCC_ObjCInterface) | (1LL << CodeCompletionContext::CCC_ObjCImplementation) | (1LL << CodeCompletionContext::CCC_ObjCIvarList) | (1LL << CodeCompletionContext::CCC_ClassStructUnion) | (1LL << CodeCompletionContext::CCC_Statement) | (1LL << CodeCompletionContext::CCC_Expression) | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) | (1LL << CodeCompletionContext::CCC_MacroNameUse) | (1LL << CodeCompletionContext::CCC_PreprocessorExpression) | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) | (1LL << CodeCompletionContext::CCC_OtherWithMacros); CachedResult.Priority = R.Priority; CachedResult.Kind = R.CursorKind; CachedResult.Availability = R.Availability; CachedResult.TypeClass = STC_Void; CachedResult.Type = 0; CachedCompletionResults.push_back(CachedResult); break; } } } // Save the current top-level hash value. CompletionCacheTopLevelHashValue = CurrentTopLevelHashValue; } void ASTUnit::ClearCachedCompletionResults() { CachedCompletionResults.clear(); CachedCompletionTypes.clear(); CachedCompletionAllocator = nullptr; } namespace { /// \brief Gathers information from ASTReader that will be used to initialize /// a Preprocessor. class ASTInfoCollector : public ASTReaderListener { Preprocessor &PP; ASTContext &Context; LangOptions &LangOpt; std::shared_ptr &TargetOpts; IntrusiveRefCntPtr &Target; unsigned &Counter; bool InitializedLanguage; public: ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt, std::shared_ptr &TargetOpts, IntrusiveRefCntPtr &Target, unsigned &Counter) : PP(PP), Context(Context), LangOpt(LangOpt), TargetOpts(TargetOpts), Target(Target), Counter(Counter), InitializedLanguage(false) {} bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) override { if (InitializedLanguage) return false; LangOpt = LangOpts; InitializedLanguage = true; updated(); return false; } bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) override { // If we've already initialized the target, don't do it again. if (Target) return false; this->TargetOpts = std::make_shared(TargetOpts); Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), this->TargetOpts); updated(); return false; } void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override { Counter = Value; } private: void updated() { if (!Target || !InitializedLanguage) return; // Inform the target of the language options. // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. Target->adjust(LangOpt); // Initialize the preprocessor. PP.Initialize(*Target); // Initialize the ASTContext Context.InitBuiltinTypes(*Target); // We didn't have access to the comment options when the ASTContext was // constructed, so register them now. Context.getCommentCommandTraits().registerCommentOptions( LangOpt.CommentOpts); } }; /// \brief Diagnostic consumer that saves each diagnostic it is given. class StoredDiagnosticConsumer : public DiagnosticConsumer { SmallVectorImpl &StoredDiags; SourceManager *SourceMgr; public: explicit StoredDiagnosticConsumer( SmallVectorImpl &StoredDiags) : StoredDiags(StoredDiags), SourceMgr(nullptr) {} void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP = nullptr) override { if (PP) SourceMgr = &PP->getSourceManager(); } void HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) override; }; /// \brief RAII object that optionally captures diagnostics, if /// there is no diagnostic client to capture them already. class CaptureDroppedDiagnostics { DiagnosticsEngine &Diags; StoredDiagnosticConsumer Client; DiagnosticConsumer *PreviousClient; std::unique_ptr OwningPreviousClient; public: CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags, SmallVectorImpl &StoredDiags) : Diags(Diags), Client(StoredDiags), PreviousClient(nullptr) { if (RequestCapture || Diags.getClient() == nullptr) { OwningPreviousClient = Diags.takeClient(); PreviousClient = Diags.getClient(); Diags.setClient(&Client, false); } } ~CaptureDroppedDiagnostics() { if (Diags.getClient() == &Client) Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); } }; } // anonymous namespace void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) { // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); // Only record the diagnostic if it's part of the source manager we know // about. This effectively drops diagnostics from modules we're building. // FIXME: In the long run, ee don't want to drop source managers from modules. if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) StoredDiags.emplace_back(Level, Info); } IntrusiveRefCntPtr ASTUnit::getASTReader() const { return Reader; } ASTMutationListener *ASTUnit::getASTMutationListener() { if (WriterData) return &WriterData->Writer; return nullptr; } ASTDeserializationListener *ASTUnit::getDeserializationListener() { if (WriterData) return &WriterData->Writer; return nullptr; } std::unique_ptr ASTUnit::getBufferForFile(StringRef Filename, std::string *ErrorStr) { assert(FileMgr); auto Buffer = FileMgr->getBufferForFile(Filename); if (Buffer) return std::move(*Buffer); if (ErrorStr) *ErrorStr = Buffer.getError().message(); return nullptr; } /// \brief Configure the diagnostics object for use with ASTUnit. void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr Diags, ASTUnit &AST, bool CaptureDiagnostics) { assert(Diags.get() && "no DiagnosticsEngine was provided"); if (CaptureDiagnostics) Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); } std::unique_ptr ASTUnit::LoadFromASTFile( const std::string &Filename, const PCHContainerReader &PCHContainerRdr, IntrusiveRefCntPtr Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo, bool OnlyLocalDecls, ArrayRef RemappedFiles, bool CaptureDiagnostics, bool AllowPCHWithCompilerErrors, bool UserFilesAreVolatile) { std::unique_ptr AST(new ASTUnit(true)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); llvm::CrashRecoveryContextCleanupRegistrar > DiagCleanup(Diags.get()); ConfigureDiags(Diags, *AST, CaptureDiagnostics); AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->Diagnostics = Diags; IntrusiveRefCntPtr VFS = vfs::getRealFileSystem(); AST->FileMgr = new FileManager(FileSystemOpts, VFS); AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->SourceMgr = new SourceManager(AST->getDiagnostics(), AST->getFileManager(), UserFilesAreVolatile); AST->PCMCache = new MemoryBufferCache; AST->HSOpts = std::make_shared(); AST->HSOpts->ModuleFormat = PCHContainerRdr.getFormat(); AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts, AST->getSourceManager(), AST->getDiagnostics(), AST->ASTFileLangOpts, /*Target=*/nullptr)); auto PPOpts = std::make_shared(); for (const auto &RemappedFile : RemappedFiles) PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second); // Gather Info for preprocessor construction later on. HeaderSearch &HeaderInfo = *AST->HeaderInfo; unsigned Counter; AST->PP = std::make_shared( std::move(PPOpts), AST->getDiagnostics(), AST->ASTFileLangOpts, AST->getSourceManager(), *AST->PCMCache, HeaderInfo, *AST, /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false); Preprocessor &PP = *AST->PP; AST->Ctx = new ASTContext(AST->ASTFileLangOpts, AST->getSourceManager(), PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo()); ASTContext &Context = *AST->Ctx; bool disableValid = false; if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION")) disableValid = true; AST->Reader = new ASTReader(PP, Context, PCHContainerRdr, { }, /*isysroot=*/"", /*DisableValidation=*/disableValid, AllowPCHWithCompilerErrors); AST->Reader->setListener(llvm::make_unique( *AST->PP, Context, AST->ASTFileLangOpts, AST->TargetOpts, AST->Target, Counter)); // Attach the AST reader to the AST context as an external AST // source, so that declarations will be deserialized from the // AST file as needed. // We need the external source to be set up before we read the AST, because // eagerly-deserialized declarations may use it. Context.setExternalSource(AST->Reader); switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile, SourceLocation(), ASTReader::ARR_None)) { case ASTReader::Success: break; case ASTReader::Failure: case ASTReader::Missing: case ASTReader::OutOfDate: case ASTReader::VersionMismatch: case ASTReader::ConfigurationMismatch: case ASTReader::HadErrors: AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch); return nullptr; } AST->OriginalSourceFile = AST->Reader->getOriginalSourceFile(); PP.setCounterValue(Counter); // Create an AST consumer, even though it isn't used. AST->Consumer.reset(new ASTConsumer); // Create a semantic analysis object and tell the AST reader about it. AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer)); AST->TheSema->Initialize(); AST->Reader->InitializeSema(*AST->TheSema); // Tell the diagnostic client that we have started a source file. AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP); return AST; } namespace { /// \brief Preprocessor callback class that updates a hash value with the names /// of all macros that have been defined by the translation unit. class MacroDefinitionTrackerPPCallbacks : public PPCallbacks { unsigned &Hash; public: explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { } void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override { Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash); } }; /// \brief Add the given declaration to the hash of all top-level entities. void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) { if (!D) return; DeclContext *DC = D->getDeclContext(); if (!DC) return; if (!(DC->isTranslationUnit() || DC->getLookupParent()->isTranslationUnit())) return; if (NamedDecl *ND = dyn_cast(D)) { if (EnumDecl *EnumD = dyn_cast(D)) { // For an unscoped enum include the enumerators in the hash since they // enter the top-level namespace. if (!EnumD->isScoped()) { for (const auto *EI : EnumD->enumerators()) { if (EI->getIdentifier()) Hash = llvm::HashString(EI->getIdentifier()->getName(), Hash); } } } if (ND->getIdentifier()) Hash = llvm::HashString(ND->getIdentifier()->getName(), Hash); else if (DeclarationName Name = ND->getDeclName()) { std::string NameStr = Name.getAsString(); Hash = llvm::HashString(NameStr, Hash); } return; } if (ImportDecl *ImportD = dyn_cast(D)) { if (Module *Mod = ImportD->getImportedModule()) { std::string ModName = Mod->getFullModuleName(); Hash = llvm::HashString(ModName, Hash); } return; } } class TopLevelDeclTrackerConsumer : public ASTConsumer { ASTUnit &Unit; unsigned &Hash; public: TopLevelDeclTrackerConsumer(ASTUnit &_Unit, unsigned &Hash) : Unit(_Unit), Hash(Hash) { Hash = 0; } void handleTopLevelDecl(Decl *D) { if (!D) return; // FIXME: Currently ObjC method declarations are incorrectly being // reported as top-level declarations, even though their DeclContext // is the containing ObjC @interface/@implementation. This is a // fundamental problem in the parser right now. if (isa(D)) return; AddTopLevelDeclarationToHash(D, Hash); Unit.addTopLevelDecl(D); handleFileLevelDecl(D); } void handleFileLevelDecl(Decl *D) { Unit.addFileLevelDecl(D); if (NamespaceDecl *NSD = dyn_cast(D)) { for (auto *I : NSD->decls()) handleFileLevelDecl(I); } } bool HandleTopLevelDecl(DeclGroupRef D) override { for (Decl *TopLevelDecl : D) handleTopLevelDecl(TopLevelDecl); return true; } // We're not interested in "interesting" decls. void HandleInterestingDecl(DeclGroupRef) override {} void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override { for (Decl *TopLevelDecl : D) handleTopLevelDecl(TopLevelDecl); } ASTMutationListener *GetASTMutationListener() override { return Unit.getASTMutationListener(); } ASTDeserializationListener *GetASTDeserializationListener() override { return Unit.getDeserializationListener(); } }; class TopLevelDeclTrackerAction : public ASTFrontendAction { public: ASTUnit &Unit; std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override { CI.getPreprocessor().addPPCallbacks( llvm::make_unique( Unit.getCurrentTopLevelHashValue())); return llvm::make_unique( Unit, Unit.getCurrentTopLevelHashValue()); } public: TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} bool hasCodeCompletionSupport() const override { return false; } TranslationUnitKind getTranslationUnitKind() override { return Unit.getTranslationUnitKind(); } }; class PrecompilePreambleAction : public ASTFrontendAction { ASTUnit &Unit; bool HasEmittedPreamblePCH; public: explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit), HasEmittedPreamblePCH(false) {} std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; } void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; } bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); } bool hasCodeCompletionSupport() const override { return false; } bool hasASTFileSupport() const override { return false; } TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; } }; class PrecompilePreambleConsumer : public PCHGenerator { ASTUnit &Unit; unsigned &Hash; std::vector TopLevelDecls; PrecompilePreambleAction *Action; std::unique_ptr Out; public: PrecompilePreambleConsumer(ASTUnit &Unit, PrecompilePreambleAction *Action, const Preprocessor &PP, StringRef isysroot, std::unique_ptr Out) : PCHGenerator(PP, "", isysroot, std::make_shared(), ArrayRef>(), /*AllowASTWithErrors=*/true), Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action), Out(std::move(Out)) { Hash = 0; } bool HandleTopLevelDecl(DeclGroupRef DG) override { for (Decl *D : DG) { // FIXME: Currently ObjC method declarations are incorrectly being // reported as top-level declarations, even though their DeclContext // is the containing ObjC @interface/@implementation. This is a // fundamental problem in the parser right now. if (isa(D)) continue; AddTopLevelDeclarationToHash(D, Hash); TopLevelDecls.push_back(D); } return true; } void HandleTranslationUnit(ASTContext &Ctx) override { PCHGenerator::HandleTranslationUnit(Ctx); if (hasEmittedPCH()) { // Write the generated bitstream to "Out". *Out << getPCH(); // Make sure it hits disk now. Out->flush(); // Free the buffer. llvm::SmallVector Empty; getPCH() = std::move(Empty); // Translate the top-level declarations we captured during // parsing into declaration IDs in the precompiled // preamble. This will allow us to deserialize those top-level // declarations when requested. for (Decl *D : TopLevelDecls) { // Invalid top-level decls may not have been serialized. if (D->isInvalidDecl()) continue; Unit.addTopLevelDeclFromPreamble(getWriter().getDeclID(D)); } Action->setHasEmittedPreamblePCH(); } } }; } // anonymous namespace std::unique_ptr PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::string Sysroot; std::string OutputFile; std::unique_ptr OS = GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile); if (!OS) return nullptr; if (!CI.getFrontendOpts().RelocatablePCH) Sysroot.clear(); CI.getPreprocessor().addPPCallbacks( llvm::make_unique( Unit.getCurrentTopLevelHashValue())); return llvm::make_unique( Unit, this, CI.getPreprocessor(), Sysroot, std::move(OS)); } static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) { return StoredDiag.getLocation().isValid(); } static void checkAndRemoveNonDriverDiags(SmallVectorImpl &StoredDiags) { // Get rid of stored diagnostics except the ones from the driver which do not // have a source location. StoredDiags.erase( std::remove_if(StoredDiags.begin(), StoredDiags.end(), isNonDriverDiag), StoredDiags.end()); } static void checkAndSanitizeDiags(SmallVectorImpl & StoredDiagnostics, SourceManager &SM) { // The stored diagnostic has the old source manager in it; update // the locations to refer into the new source manager. Since we've // been careful to make sure that the source manager's state // before and after are identical, so that we can reuse the source // location itself. for (StoredDiagnostic &SD : StoredDiagnostics) { if (SD.getLocation().isValid()) { FullSourceLoc Loc(SD.getLocation(), SM); SD.setLocation(Loc); } } } /// Parse the source file into a translation unit using the given compiler /// invocation, replacing the current translation unit. /// /// \returns True if a failure occurred that causes the ASTUnit not to /// contain any translation-unit information, false otherwise. bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, std::unique_ptr OverrideMainBuffer) { SavedMainFileBuffer.reset(); if (!Invocation) return true; // Create the compiler instance to use for building the AST. std::unique_ptr Clang( new CompilerInstance(std::move(PCHContainerOps))); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar CICleanup(Clang.get()); Clang->setInvocation(std::make_shared(*Invocation)); OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. Clang->setDiagnostics(&getDiagnostics()); // Create the target instance. Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); if (!Clang->hasTarget()) return true; // Inform the target of the language options. // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. Clang->getTarget().adjust(Clang->getLangOpts()); assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == InputKind::Source && "FIXME: AST inputs not yet supported here!"); assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != InputKind::LLVM_IR && "IR inputs not support here!"); // Configure the various subsystems. LangOpts = Clang->getInvocation().LangOpts; FileSystemOpts = Clang->getFileSystemOpts(); if (!FileMgr) { Clang->createFileManager(); FileMgr = &Clang->getFileManager(); } SourceMgr = new SourceManager(getDiagnostics(), *FileMgr, UserFilesAreVolatile); TheSema.reset(); Ctx = nullptr; PP = nullptr; Reader = nullptr; // Clear out old caches and data. TopLevelDecls.clear(); clearFileLevelDecls(); - CleanTemporaryFiles(); if (!OverrideMainBuffer) { checkAndRemoveNonDriverDiags(StoredDiagnostics); TopLevelDeclsInPreamble.clear(); } // Create a file manager object to provide access to and cache the filesystem. Clang->setFileManager(&getFileManager()); // Create the source manager. Clang->setSourceManager(&getSourceManager()); // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer.get()); PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this); PreprocessorOpts.DisablePCHValidation = true; // The stored diagnostic has the old source manager in it; update // the locations to refer into the new source manager. Since we've // been careful to make sure that the source manager's state // before and after are identical, so that we can reuse the source // location itself. checkAndSanitizeDiags(StoredDiagnostics, getSourceManager()); // Keep track of the override buffer; SavedMainFileBuffer = std::move(OverrideMainBuffer); } std::unique_ptr Act( new TopLevelDeclTrackerAction(*this)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar ActCleanup(Act.get()); if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) goto error; if (SavedMainFileBuffer) TranslateStoredDiagnostics(getFileManager(), getSourceManager(), PreambleDiagnostics, StoredDiagnostics); if (!Act->Execute()) goto error; transferASTDataFromCompilerInstance(*Clang); Act->EndSourceFile(); FailedParseDiagnostics.clear(); return false; error: // Remove the overridden buffer we used for the preamble. SavedMainFileBuffer = nullptr; // Keep the ownership of the data in the ASTUnit because the client may // want to see the diagnostics. transferASTDataFromCompilerInstance(*Clang); FailedParseDiagnostics.swap(StoredDiagnostics); StoredDiagnostics.clear(); NumStoredDiagnosticsFromDriver = 0; return true; } /// \brief Simple function to retrieve a path for a preamble precompiled header. static std::string GetPreamblePCHPath() { // FIXME: This is a hack so that we can override the preamble file during // crash-recovery testing, which is the only case where the preamble files // are not necessarily cleaned up. const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); if (TmpFile) return TmpFile; SmallString<128> Path; llvm::sys::fs::createTemporaryFile("preamble", "pch", Path); return Path.str(); } /// \brief Compute the preamble for the main file, providing the source buffer /// that corresponds to the main file along with a pair (bytes, start-of-line) /// that describes the preamble. ASTUnit::ComputedPreamble ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) { FrontendOptions &FrontendOpts = Invocation.getFrontendOpts(); PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts(); // Try to determine if the main file has been remapped, either from the // command line (to another file) or directly through the compiler invocation // (to a memory buffer). llvm::MemoryBuffer *Buffer = nullptr; std::unique_ptr BufferOwner; std::string MainFilePath(FrontendOpts.Inputs[0].getFile()); llvm::sys::fs::UniqueID MainFileID; if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) { // Check whether there is a file-file remapping of the main file for (const auto &RF : PreprocessorOpts.RemappedFiles) { std::string MPath(RF.first); llvm::sys::fs::UniqueID MID; if (!llvm::sys::fs::getUniqueID(MPath, MID)) { if (MainFileID == MID) { // We found a remapping. Try to load the resulting, remapped source. BufferOwner = getBufferForFile(RF.second); if (!BufferOwner) return ComputedPreamble(nullptr, nullptr, 0, true); } } } // Check whether there is a file-buffer remapping. It supercedes the // file-file remapping. for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { std::string MPath(RB.first); llvm::sys::fs::UniqueID MID; if (!llvm::sys::fs::getUniqueID(MPath, MID)) { if (MainFileID == MID) { // We found a remapping. BufferOwner.reset(); Buffer = const_cast(RB.second); } } } } // If the main source file was not remapped, load it now. if (!Buffer && !BufferOwner) { BufferOwner = getBufferForFile(FrontendOpts.Inputs[0].getFile()); if (!BufferOwner) return ComputedPreamble(nullptr, nullptr, 0, true); } if (!Buffer) Buffer = BufferOwner.get(); auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), *Invocation.getLangOpts(), MaxLines); return ComputedPreamble(Buffer, std::move(BufferOwner), Pre.first, Pre.second); } ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) { PreambleFileHash Result; Result.Size = Size; Result.ModTime = ModTime; Result.MD5 = {}; return Result; } ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForMemoryBuffer( const llvm::MemoryBuffer *Buffer) { PreambleFileHash Result; Result.Size = Buffer->getBufferSize(); Result.ModTime = 0; llvm::MD5 MD5Ctx; MD5Ctx.update(Buffer->getBuffer().data()); MD5Ctx.final(Result.MD5); return Result; } namespace clang { bool operator==(const ASTUnit::PreambleFileHash &LHS, const ASTUnit::PreambleFileHash &RHS) { return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && LHS.MD5 == RHS.MD5; } } // namespace clang static std::pair makeStandaloneRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts) { CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts); unsigned Offset = SM.getFileOffset(FileRange.getBegin()); unsigned EndOffset = SM.getFileOffset(FileRange.getEnd()); return std::make_pair(Offset, EndOffset); } static ASTUnit::StandaloneFixIt makeStandaloneFixIt(const SourceManager &SM, const LangOptions &LangOpts, const FixItHint &InFix) { ASTUnit::StandaloneFixIt OutFix; OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts); OutFix.InsertFromRange = makeStandaloneRange(InFix.InsertFromRange, SM, LangOpts); OutFix.CodeToInsert = InFix.CodeToInsert; OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions; return OutFix; } static ASTUnit::StandaloneDiagnostic makeStandaloneDiagnostic(const LangOptions &LangOpts, const StoredDiagnostic &InDiag) { ASTUnit::StandaloneDiagnostic OutDiag; OutDiag.ID = InDiag.getID(); OutDiag.Level = InDiag.getLevel(); OutDiag.Message = InDiag.getMessage(); OutDiag.LocOffset = 0; if (InDiag.getLocation().isInvalid()) return OutDiag; const SourceManager &SM = InDiag.getLocation().getManager(); SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation()); OutDiag.Filename = SM.getFilename(FileLoc); if (OutDiag.Filename.empty()) return OutDiag; OutDiag.LocOffset = SM.getFileOffset(FileLoc); for (const CharSourceRange &Range : InDiag.getRanges()) OutDiag.Ranges.push_back(makeStandaloneRange(Range, SM, LangOpts)); for (const FixItHint &FixIt : InDiag.getFixIts()) OutDiag.FixIts.push_back(makeStandaloneFixIt(SM, LangOpts, FixIt)); return OutDiag; } /// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing /// the source file. /// /// This routine will compute the preamble of the main source file. If a /// non-trivial preamble is found, it will precompile that preamble into a /// precompiled header so that the precompiled preamble can be used to reduce /// reparsing time. If a precompiled preamble has already been constructed, /// this routine will determine if it is still valid and, if so, avoid /// rebuilding the precompiled preamble. /// /// \param AllowRebuild When true (the default), this routine is /// allowed to rebuild the precompiled preamble if it is found to be /// out-of-date. /// /// \param MaxLines When non-zero, the maximum number of lines that /// can occur within the preamble. /// /// \returns If the precompiled preamble can be used, returns a newly-allocated /// buffer that should be used in place of the main file when doing so. /// Otherwise, returns a NULL pointer. std::unique_ptr ASTUnit::getMainBufferWithPrecompiledPreamble( std::shared_ptr PCHContainerOps, const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild, unsigned MaxLines) { auto PreambleInvocation = std::make_shared(PreambleInvocationIn); FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts(); PreprocessorOptions &PreprocessorOpts = PreambleInvocation->getPreprocessorOpts(); ComputedPreamble NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines); if (!NewPreamble.Size) { // We couldn't find a preamble in the main source. Clear out the current // preamble, if we have one. It's obviously no good any more. Preamble.clear(); erasePreambleFile(this); // The next time we actually see a preamble, precompile it. PreambleRebuildCounter = 1; return nullptr; } if (!Preamble.empty()) { // We've previously computed a preamble. Check whether we have the same // preamble now that we did before, and that there's enough space in // the main-file buffer within the precompiled preamble to fit the // new main file. if (Preamble.size() == NewPreamble.Size && PreambleEndsAtStartOfLine == NewPreamble.PreambleEndsAtStartOfLine && memcmp(Preamble.getBufferStart(), NewPreamble.Buffer->getBufferStart(), NewPreamble.Size) == 0) { // The preamble has not changed. We may be able to re-use the precompiled // preamble. // Check that none of the files used by the preamble have changed. bool AnyFileChanged = false; // First, make a record of those files that have been overridden via // remapping or unsaved_files. std::map OverriddenFiles; for (const auto &R : PreprocessorOpts.RemappedFiles) { if (AnyFileChanged) break; vfs::Status Status; if (FileMgr->getNoncachedStatValue(R.second, Status)) { // If we can't stat the file we're remapping to, assume that something // horrible happened. AnyFileChanged = true; break; } OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile( Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime())); } for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { if (AnyFileChanged) break; vfs::Status Status; if (FileMgr->getNoncachedStatValue(RB.first, Status)) { AnyFileChanged = true; break; } OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForMemoryBuffer(RB.second); } // Check whether anything has changed. for (llvm::StringMap::iterator F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end(); !AnyFileChanged && F != FEnd; ++F) { vfs::Status Status; if (FileMgr->getNoncachedStatValue(F->first(), Status)) { // If we can't stat the file, assume that something horrible happened. AnyFileChanged = true; break; } std::map::iterator Overridden = OverriddenFiles.find(Status.getUniqueID()); if (Overridden != OverriddenFiles.end()) { // This file was remapped; check whether the newly-mapped file // matches up with the previous mapping. if (Overridden->second != F->second) AnyFileChanged = true; continue; } // The file was not remapped; check whether it has changed on disk. if (Status.getSize() != uint64_t(F->second.Size) || llvm::sys::toTimeT(Status.getLastModificationTime()) != F->second.ModTime) AnyFileChanged = true; } if (!AnyFileChanged) { // Okay! We can re-use the precompiled preamble. // Set the state of the diagnostic object to mimic its state // after parsing the preamble. getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), PreambleInvocation->getDiagnosticOpts()); getDiagnostics().setNumWarnings(NumWarningsInPreamble); return llvm::MemoryBuffer::getMemBufferCopy( NewPreamble.Buffer->getBuffer(), FrontendOpts.Inputs[0].getFile()); } } // If we aren't allowed to rebuild the precompiled preamble, just // return now. if (!AllowRebuild) return nullptr; // We can't reuse the previously-computed preamble. Build a new one. Preamble.clear(); PreambleDiagnostics.clear(); erasePreambleFile(this); PreambleRebuildCounter = 1; } else if (!AllowRebuild) { // We aren't allowed to rebuild the precompiled preamble; just // return now. return nullptr; } // If the preamble rebuild counter > 1, it's because we previously // failed to build a preamble and we're not yet ready to try // again. Decrement the counter and return a failure. if (PreambleRebuildCounter > 1) { --PreambleRebuildCounter; return nullptr; } // Create a temporary file for the precompiled preamble. In rare // circumstances, this can fail. std::string PreamblePCHPath = GetPreamblePCHPath(); if (PreamblePCHPath.empty()) { // Try again next time. PreambleRebuildCounter = 1; return nullptr; } // We did not previously compute a preamble, or it can't be reused anyway. SimpleTimer PreambleTimer(WantTiming); PreambleTimer.setOutput("Precompiling preamble"); // Save the preamble text for later; we'll need to compare against it for // subsequent reparses. StringRef MainFilename = FrontendOpts.Inputs[0].getFile(); Preamble.assign(FileMgr->getFile(MainFilename), NewPreamble.Buffer->getBufferStart(), NewPreamble.Buffer->getBufferStart() + NewPreamble.Size); PreambleEndsAtStartOfLine = NewPreamble.PreambleEndsAtStartOfLine; PreambleBuffer = llvm::MemoryBuffer::getMemBufferCopy( NewPreamble.Buffer->getBuffer().slice(0, Preamble.size()), MainFilename); // Remap the main source file to the preamble buffer. StringRef MainFilePath = FrontendOpts.Inputs[0].getFile(); PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer.get()); // Tell the compiler invocation to generate a temporary precompiled header. FrontendOpts.ProgramAction = frontend::GeneratePCH; // FIXME: Generate the precompiled header into memory? FrontendOpts.OutputFile = PreamblePCHPath; PreprocessorOpts.PrecompiledPreambleBytes.first = 0; PreprocessorOpts.PrecompiledPreambleBytes.second = false; // Create the compiler instance to use for building the precompiled preamble. std::unique_ptr Clang( new CompilerInstance(std::move(PCHContainerOps))); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar CICleanup(Clang.get()); Clang->setInvocation(std::move(PreambleInvocation)); OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing all of the diagnostics produced. Clang->setDiagnostics(&getDiagnostics()); // Create the target instance. Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); if (!Clang->hasTarget()) { llvm::sys::fs::remove(FrontendOpts.OutputFile); Preamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.RemappedFileBuffers.pop_back(); return nullptr; } // Inform the target of the language options. // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. Clang->getTarget().adjust(Clang->getLangOpts()); assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == InputKind::Source && "FIXME: AST inputs not yet supported here!"); assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != InputKind::LLVM_IR && "IR inputs not support here!"); // Clear out old caches and data. getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts()); checkAndRemoveNonDriverDiags(StoredDiagnostics); TopLevelDecls.clear(); TopLevelDeclsInPreamble.clear(); PreambleDiagnostics.clear(); IntrusiveRefCntPtr VFS = createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics()); if (!VFS) return nullptr; // Create a file manager object to provide access to and cache the filesystem. Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); // Create the source manager. Clang->setSourceManager(new SourceManager(getDiagnostics(), Clang->getFileManager())); auto PreambleDepCollector = std::make_shared(); Clang->addDependencyCollector(PreambleDepCollector); std::unique_ptr Act; Act.reset(new PrecompilePreambleAction(*this)); if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { llvm::sys::fs::remove(FrontendOpts.OutputFile); Preamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.RemappedFileBuffers.pop_back(); return nullptr; } Act->Execute(); // Transfer any diagnostics generated when parsing the preamble into the set // of preamble diagnostics. for (stored_diag_iterator I = stored_diag_afterDriver_begin(), E = stored_diag_end(); I != E; ++I) PreambleDiagnostics.push_back( makeStandaloneDiagnostic(Clang->getLangOpts(), *I)); Act->EndSourceFile(); checkAndRemoveNonDriverDiags(StoredDiagnostics); if (!Act->hasEmittedPreamblePCH()) { // The preamble PCH failed (e.g. there was a module loading fatal error), // so no precompiled header was generated. Forget that we even tried. // FIXME: Should we leave a note for ourselves to try again? llvm::sys::fs::remove(FrontendOpts.OutputFile); Preamble.clear(); TopLevelDeclsInPreamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.RemappedFileBuffers.pop_back(); return nullptr; } // Keep track of the preamble we precompiled. setPreambleFile(this, FrontendOpts.OutputFile); NumWarningsInPreamble = getDiagnostics().getNumWarnings(); // Keep track of all of the files that the source manager knows about, // so we can verify whether they have changed or not. FilesInPreamble.clear(); SourceManager &SourceMgr = Clang->getSourceManager(); for (auto &Filename : PreambleDepCollector->getDependencies()) { const FileEntry *File = Clang->getFileManager().getFile(Filename); if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())) continue; if (time_t ModTime = File->getModificationTime()) { FilesInPreamble[File->getName()] = PreambleFileHash::createForFile( File->getSize(), ModTime); } else { llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); FilesInPreamble[File->getName()] = PreambleFileHash::createForMemoryBuffer(Buffer); } } PreambleRebuildCounter = 1; PreprocessorOpts.RemappedFileBuffers.pop_back(); // If the hash of top-level entities differs from the hash of the top-level // entities the last time we rebuilt the preamble, clear out the completion // cache. if (CurrentTopLevelHashValue != PreambleTopLevelHashValue) { CompletionCacheTopLevelHashValue = 0; PreambleTopLevelHashValue = CurrentTopLevelHashValue; } return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.Buffer->getBuffer(), MainFilename); } void ASTUnit::RealizeTopLevelDeclsFromPreamble() { std::vector Resolved; Resolved.reserve(TopLevelDeclsInPreamble.size()); ExternalASTSource &Source = *getASTContext().getExternalSource(); for (serialization::DeclID TopLevelDecl : TopLevelDeclsInPreamble) { // Resolve the declaration ID to an actual declaration, possibly // deserializing the declaration in the process. if (Decl *D = Source.GetExternalDecl(TopLevelDecl)) Resolved.push_back(D); } TopLevelDeclsInPreamble.clear(); TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end()); } void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) { // Steal the created target, context, and preprocessor if they have been // created. assert(CI.hasInvocation() && "missing invocation"); LangOpts = CI.getInvocation().LangOpts; TheSema = CI.takeSema(); Consumer = CI.takeASTConsumer(); if (CI.hasASTContext()) Ctx = &CI.getASTContext(); if (CI.hasPreprocessor()) PP = CI.getPreprocessorPtr(); CI.setSourceManager(nullptr); CI.setFileManager(nullptr); if (CI.hasTarget()) Target = &CI.getTarget(); Reader = CI.getModuleManager(); HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure(); } StringRef ASTUnit::getMainFileName() const { if (Invocation && !Invocation->getFrontendOpts().Inputs.empty()) { const FrontendInputFile &Input = Invocation->getFrontendOpts().Inputs[0]; if (Input.isFile()) return Input.getFile(); else return Input.getBuffer()->getBufferIdentifier(); } if (SourceMgr) { if (const FileEntry * FE = SourceMgr->getFileEntryForID(SourceMgr->getMainFileID())) return FE->getName(); } return StringRef(); } StringRef ASTUnit::getASTFileName() const { if (!isMainFileAST()) return StringRef(); serialization::ModuleFile & Mod = Reader->getModuleManager().getPrimaryModule(); return Mod.FileName; } std::unique_ptr ASTUnit::create(std::shared_ptr CI, IntrusiveRefCntPtr Diags, bool CaptureDiagnostics, bool UserFilesAreVolatile) { std::unique_ptr AST(new ASTUnit(false)); ConfigureDiags(Diags, *AST, CaptureDiagnostics); IntrusiveRefCntPtr VFS = createVFSFromCompilerInvocation(*CI, *Diags); if (!VFS) return nullptr; AST->Diagnostics = Diags; AST->FileSystemOpts = CI->getFileSystemOpts(); AST->Invocation = std::move(CI); AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr, UserFilesAreVolatile); AST->PCMCache = new MemoryBufferCache; return AST; } ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( std::shared_ptr CI, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FrontendAction *Action, ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath, bool OnlyLocalDecls, bool CaptureDiagnostics, unsigned PrecompilePreambleAfterNParses, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile, std::unique_ptr *ErrAST) { assert(CI && "A CompilerInvocation is required"); std::unique_ptr OwnAST; ASTUnit *AST = Unit; if (!AST) { // Create the AST unit. OwnAST = create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile); AST = OwnAST.get(); if (!AST) return nullptr; } if (!ResourceFilesPath.empty()) { // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; } AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; if (PrecompilePreambleAfterNParses > 0) AST->PreambleRebuildCounter = PrecompilePreambleAfterNParses; AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->IncludeBriefCommentsInCodeCompletion = IncludeBriefCommentsInCodeCompletion; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(OwnAST.get()); llvm::CrashRecoveryContextCleanupRegistrar > DiagCleanup(Diags.get()); // We'll manage file buffers ourselves. CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; CI->getFrontendOpts().DisableFree = false; ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts()); // Create the compiler instance to use for building the AST. std::unique_ptr Clang( new CompilerInstance(std::move(PCHContainerOps))); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar CICleanup(Clang.get()); Clang->setInvocation(std::move(CI)); AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. Clang->setDiagnostics(&AST->getDiagnostics()); // Create the target instance. Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); if (!Clang->hasTarget()) return nullptr; // Inform the target of the language options. // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. Clang->getTarget().adjust(Clang->getLangOpts()); assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == InputKind::Source && "FIXME: AST inputs not yet supported here!"); assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != InputKind::LLVM_IR && "IR inputs not support here!"); // Configure the various subsystems. AST->TheSema.reset(); AST->Ctx = nullptr; AST->PP = nullptr; AST->Reader = nullptr; // Create a file manager object to provide access to and cache the filesystem. Clang->setFileManager(&AST->getFileManager()); // Create the source manager. Clang->setSourceManager(&AST->getSourceManager()); FrontendAction *Act = Action; std::unique_ptr TrackerAct; if (!Act) { TrackerAct.reset(new TopLevelDeclTrackerAction(*AST)); Act = TrackerAct.get(); } // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar ActCleanup(TrackerAct.get()); if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { AST->transferASTDataFromCompilerInstance(*Clang); if (OwnAST && ErrAST) ErrAST->swap(OwnAST); return nullptr; } if (Persistent && !TrackerAct) { Clang->getPreprocessor().addPPCallbacks( llvm::make_unique( AST->getCurrentTopLevelHashValue())); std::vector> Consumers; if (Clang->hasASTConsumer()) Consumers.push_back(Clang->takeASTConsumer()); Consumers.push_back(llvm::make_unique( *AST, AST->getCurrentTopLevelHashValue())); Clang->setASTConsumer( llvm::make_unique(std::move(Consumers))); } if (!Act->Execute()) { AST->transferASTDataFromCompilerInstance(*Clang); if (OwnAST && ErrAST) ErrAST->swap(OwnAST); return nullptr; } // Steal the created target, context, and preprocessor. AST->transferASTDataFromCompilerInstance(*Clang); Act->EndSourceFile(); if (OwnAST) return OwnAST.release(); else return AST; } bool ASTUnit::LoadFromCompilerInvocation( std::shared_ptr PCHContainerOps, unsigned PrecompilePreambleAfterNParses) { if (!Invocation) return true; // We'll manage file buffers ourselves. Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true; Invocation->getFrontendOpts().DisableFree = false; getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); std::unique_ptr OverrideMainBuffer; if (PrecompilePreambleAfterNParses > 0) { PreambleRebuildCounter = PrecompilePreambleAfterNParses; OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation); getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); } SimpleTimer ParsingTimer(WantTiming); ParsingTimer.setOutput("Parsing " + getMainFileName()); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar MemBufferCleanup(OverrideMainBuffer.get()); return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer)); } std::unique_ptr ASTUnit::LoadFromCompilerInvocation( std::shared_ptr CI, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FileManager *FileMgr, bool OnlyLocalDecls, bool CaptureDiagnostics, unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) { // Create the AST unit. std::unique_ptr AST(new ASTUnit(false)); ConfigureDiags(Diags, *AST, CaptureDiagnostics); AST->Diagnostics = Diags; AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->IncludeBriefCommentsInCodeCompletion = IncludeBriefCommentsInCodeCompletion; AST->Invocation = std::move(CI); AST->FileSystemOpts = FileMgr->getFileSystemOpts(); AST->FileMgr = FileMgr; AST->UserFilesAreVolatile = UserFilesAreVolatile; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); llvm::CrashRecoveryContextCleanupRegistrar > DiagCleanup(Diags.get()); if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), PrecompilePreambleAfterNParses)) return nullptr; return AST; } ASTUnit *ASTUnit::LoadFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, bool OnlyLocalDecls, bool CaptureDiagnostics, ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, bool UserFilesAreVolatile, bool ForSerialization, llvm::Optional ModuleFormat, std::unique_ptr *ErrAST) { assert(Diags.get() && "no DiagnosticsEngine was provided"); SmallVector StoredDiagnostics; std::shared_ptr CI; { CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, StoredDiagnostics); CI = clang::createInvocationFromCommandLine( llvm::makeArrayRef(ArgBegin, ArgEnd), Diags); if (!CI) return nullptr; } // Override any files that need remapping for (const auto &RemappedFile : RemappedFiles) { CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, RemappedFile.second); } PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies; if (ModuleFormat) CI->getHeaderSearchOpts().ModuleFormat = ModuleFormat.getValue(); // Create the AST unit. std::unique_ptr AST; AST.reset(new ASTUnit(false)); ConfigureDiags(Diags, *AST, CaptureDiagnostics); AST->Diagnostics = Diags; AST->FileSystemOpts = CI->getFileSystemOpts(); IntrusiveRefCntPtr VFS = createVFSFromCompilerInvocation(*CI, *Diags); if (!VFS) return nullptr; AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); AST->PCMCache = new MemoryBufferCache; AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->IncludeBriefCommentsInCodeCompletion = IncludeBriefCommentsInCodeCompletion; AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; if (ForSerialization) AST->WriterData.reset(new ASTWriterData(*AST->PCMCache)); // Zero out now to ease cleanup during crash recovery. CI = nullptr; Diags = nullptr; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), PrecompilePreambleAfterNParses)) { // Some error occurred, if caller wants to examine diagnostics, pass it the // ASTUnit. if (ErrAST) { AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); ErrAST->swap(AST); } return nullptr; } return AST.release(); } bool ASTUnit::Reparse(std::shared_ptr PCHContainerOps, ArrayRef RemappedFiles) { if (!Invocation) return true; clearFileLevelDecls(); SimpleTimer ParsingTimer(WantTiming); ParsingTimer.setOutput("Reparsing " + getMainFileName()); // Remap files. PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); for (const auto &RB : PPOpts.RemappedFileBuffers) delete RB.second; Invocation->getPreprocessorOpts().clearRemappedFiles(); for (const auto &RemappedFile : RemappedFiles) { Invocation->getPreprocessorOpts().addRemappedFile(RemappedFile.first, RemappedFile.second); } // If we have a preamble file lying around, or if we might try to // build a precompiled preamble, do so now. std::unique_ptr OverrideMainBuffer; if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0) OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation); // Clear out the diagnostics state. FileMgr.reset(); getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); if (OverrideMainBuffer) getDiagnostics().setNumWarnings(NumWarningsInPreamble); // Parse the sources bool Result = Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer)); // If we're caching global code-completion results, and the top-level // declarations have changed, clear out the code-completion cache. if (!Result && ShouldCacheCodeCompletionResults && CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue) CacheCodeCompletionResults(); // We now need to clear out the completion info related to this translation // unit; it'll be recreated if necessary. CCTUInfo.reset(); return Result; } //----------------------------------------------------------------------------// // Code completion //----------------------------------------------------------------------------// namespace { /// \brief Code completion consumer that combines the cached code-completion /// results from an ASTUnit with the code-completion results provided to it, /// then passes the result on to class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer { uint64_t NormalContexts; ASTUnit &AST; CodeCompleteConsumer &Next; public: AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next, const CodeCompleteOptions &CodeCompleteOpts) : CodeCompleteConsumer(CodeCompleteOpts, Next.isOutputBinary()), AST(AST), Next(Next) { // Compute the set of contexts in which we will look when we don't have // any information about the specific context. NormalContexts = (1LL << CodeCompletionContext::CCC_TopLevel) | (1LL << CodeCompletionContext::CCC_ObjCInterface) | (1LL << CodeCompletionContext::CCC_ObjCImplementation) | (1LL << CodeCompletionContext::CCC_ObjCIvarList) | (1LL << CodeCompletionContext::CCC_Statement) | (1LL << CodeCompletionContext::CCC_Expression) | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) | (1LL << CodeCompletionContext::CCC_DotMemberAccess) | (1LL << CodeCompletionContext::CCC_ArrowMemberAccess) | (1LL << CodeCompletionContext::CCC_ObjCPropertyAccess) | (1LL << CodeCompletionContext::CCC_ObjCProtocolName) | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) | (1LL << CodeCompletionContext::CCC_Recovery); if (AST.getASTContext().getLangOpts().CPlusPlus) NormalContexts |= (1LL << CodeCompletionContext::CCC_EnumTag) | (1LL << CodeCompletionContext::CCC_UnionTag) | (1LL << CodeCompletionContext::CCC_ClassOrStructTag); } void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, CodeCompletionResult *Results, unsigned NumResults) override; void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates) override { Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates); } CodeCompletionAllocator &getAllocator() override { return Next.getAllocator(); } CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return Next.getCodeCompletionTUInfo(); } }; } // anonymous namespace /// \brief Helper function that computes which global names are hidden by the /// local code-completion results. static void CalculateHiddenNames(const CodeCompletionContext &Context, CodeCompletionResult *Results, unsigned NumResults, ASTContext &Ctx, llvm::StringSet &HiddenNames){ bool OnlyTagNames = false; switch (Context.getKind()) { case CodeCompletionContext::CCC_Recovery: case CodeCompletionContext::CCC_TopLevel: case CodeCompletionContext::CCC_ObjCInterface: case CodeCompletionContext::CCC_ObjCImplementation: case CodeCompletionContext::CCC_ObjCIvarList: case CodeCompletionContext::CCC_ClassStructUnion: case CodeCompletionContext::CCC_Statement: case CodeCompletionContext::CCC_Expression: case CodeCompletionContext::CCC_ObjCMessageReceiver: case CodeCompletionContext::CCC_DotMemberAccess: case CodeCompletionContext::CCC_ArrowMemberAccess: case CodeCompletionContext::CCC_ObjCPropertyAccess: case CodeCompletionContext::CCC_Namespace: case CodeCompletionContext::CCC_Type: case CodeCompletionContext::CCC_Name: case CodeCompletionContext::CCC_PotentiallyQualifiedName: case CodeCompletionContext::CCC_ParenthesizedExpression: case CodeCompletionContext::CCC_ObjCInterfaceName: break; case CodeCompletionContext::CCC_EnumTag: case CodeCompletionContext::CCC_UnionTag: case CodeCompletionContext::CCC_ClassOrStructTag: OnlyTagNames = true; break; case CodeCompletionContext::CCC_ObjCProtocolName: case CodeCompletionContext::CCC_MacroName: case CodeCompletionContext::CCC_MacroNameUse: case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_NaturalLanguage: case CodeCompletionContext::CCC_SelectorName: case CodeCompletionContext::CCC_TypeQualifiers: case CodeCompletionContext::CCC_Other: case CodeCompletionContext::CCC_OtherWithMacros: case CodeCompletionContext::CCC_ObjCInstanceMessage: case CodeCompletionContext::CCC_ObjCClassMessage: case CodeCompletionContext::CCC_ObjCCategoryName: // We're looking for nothing, or we're looking for names that cannot // be hidden. return; } typedef CodeCompletionResult Result; for (unsigned I = 0; I != NumResults; ++I) { if (Results[I].Kind != Result::RK_Declaration) continue; unsigned IDNS = Results[I].Declaration->getUnderlyingDecl()->getIdentifierNamespace(); bool Hiding = false; if (OnlyTagNames) Hiding = (IDNS & Decl::IDNS_Tag); else { unsigned HiddenIDNS = (Decl::IDNS_Type | Decl::IDNS_Member | Decl::IDNS_Namespace | Decl::IDNS_Ordinary | Decl::IDNS_NonMemberOperator); if (Ctx.getLangOpts().CPlusPlus) HiddenIDNS |= Decl::IDNS_Tag; Hiding = (IDNS & HiddenIDNS); } if (!Hiding) continue; DeclarationName Name = Results[I].Declaration->getDeclName(); if (IdentifierInfo *Identifier = Name.getAsIdentifierInfo()) HiddenNames.insert(Identifier->getName()); else HiddenNames.insert(Name.getAsString()); } } void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, CodeCompletionResult *Results, unsigned NumResults) { // Merge the results we were given with the results we cached. bool AddedResult = false; uint64_t InContexts = Context.getKind() == CodeCompletionContext::CCC_Recovery ? NormalContexts : (1LL << Context.getKind()); // Contains the set of names that are hidden by "local" completion results. llvm::StringSet HiddenNames; typedef CodeCompletionResult Result; SmallVector AllResults; for (ASTUnit::cached_completion_iterator C = AST.cached_completion_begin(), CEnd = AST.cached_completion_end(); C != CEnd; ++C) { // If the context we are in matches any of the contexts we are // interested in, we'll add this result. if ((C->ShowInContexts & InContexts) == 0) continue; // If we haven't added any results previously, do so now. if (!AddedResult) { CalculateHiddenNames(Context, Results, NumResults, S.Context, HiddenNames); AllResults.insert(AllResults.end(), Results, Results + NumResults); AddedResult = true; } // Determine whether this global completion result is hidden by a local // completion result. If so, skip it. if (C->Kind != CXCursor_MacroDefinition && HiddenNames.count(C->Completion->getTypedText())) continue; // Adjust priority based on similar type classes. unsigned Priority = C->Priority; CodeCompletionString *Completion = C->Completion; if (!Context.getPreferredType().isNull()) { if (C->Kind == CXCursor_MacroDefinition) { Priority = getMacroUsagePriority(C->Completion->getTypedText(), S.getLangOpts(), Context.getPreferredType()->isAnyPointerType()); } else if (C->Type) { CanQualType Expected = S.Context.getCanonicalType( Context.getPreferredType().getUnqualifiedType()); SimplifiedTypeClass ExpectedSTC = getSimplifiedTypeClass(Expected); if (ExpectedSTC == C->TypeClass) { // We know this type is similar; check for an exact match. llvm::StringMap &CachedCompletionTypes = AST.getCachedCompletionTypes(); llvm::StringMap::iterator Pos = CachedCompletionTypes.find(QualType(Expected).getAsString()); if (Pos != CachedCompletionTypes.end() && Pos->second == C->Type) Priority /= CCF_ExactTypeMatch; else Priority /= CCF_SimilarTypeMatch; } } } // Adjust the completion string, if required. if (C->Kind == CXCursor_MacroDefinition && Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) { // Create a new code-completion string that just contains the // macro name, without its arguments. CodeCompletionBuilder Builder(getAllocator(), getCodeCompletionTUInfo(), CCP_CodePattern, C->Availability); Builder.AddTypedTextChunk(C->Completion->getTypedText()); Priority = CCP_CodePattern; Completion = Builder.TakeString(); } AllResults.push_back(Result(Completion, Priority, C->Kind, C->Availability)); } // If we did not add any cached completion results, just forward the // results we were given to the next consumer. if (!AddedResult) { Next.ProcessCodeCompleteResults(S, Context, Results, NumResults); return; } Next.ProcessCodeCompleteResults(S, Context, AllResults.data(), AllResults.size()); } void ASTUnit::CodeComplete( StringRef File, unsigned Line, unsigned Column, ArrayRef RemappedFiles, bool IncludeMacros, bool IncludeCodePatterns, bool IncludeBriefComments, CodeCompleteConsumer &Consumer, std::shared_ptr PCHContainerOps, DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, SmallVectorImpl &StoredDiagnostics, SmallVectorImpl &OwnedBuffers) { if (!Invocation) return; SimpleTimer CompletionTimer(WantTiming); CompletionTimer.setOutput("Code completion @ " + File + ":" + Twine(Line) + ":" + Twine(Column)); auto CCInvocation = std::make_shared(*Invocation); FrontendOptions &FrontendOpts = CCInvocation->getFrontendOpts(); CodeCompleteOptions &CodeCompleteOpts = FrontendOpts.CodeCompleteOpts; PreprocessorOptions &PreprocessorOpts = CCInvocation->getPreprocessorOpts(); CodeCompleteOpts.IncludeMacros = IncludeMacros && CachedCompletionResults.empty(); CodeCompleteOpts.IncludeCodePatterns = IncludeCodePatterns; CodeCompleteOpts.IncludeGlobals = CachedCompletionResults.empty(); CodeCompleteOpts.IncludeBriefComments = IncludeBriefComments; assert(IncludeBriefComments == this->IncludeBriefCommentsInCodeCompletion); FrontendOpts.CodeCompletionAt.FileName = File; FrontendOpts.CodeCompletionAt.Line = Line; FrontendOpts.CodeCompletionAt.Column = Column; // Set the language options appropriately. LangOpts = *CCInvocation->getLangOpts(); // Spell-checking and warnings are wasteful during code-completion. LangOpts.SpellChecking = false; CCInvocation->getDiagnosticOpts().IgnoreWarnings = true; std::unique_ptr Clang( new CompilerInstance(PCHContainerOps)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar CICleanup(Clang.get()); auto &Inv = *CCInvocation; Clang->setInvocation(std::move(CCInvocation)); OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics produced. Clang->setDiagnostics(&Diag); CaptureDroppedDiagnostics Capture(true, Clang->getDiagnostics(), StoredDiagnostics); ProcessWarningOptions(Diag, Inv.getDiagnosticOpts()); // Create the target instance. Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); if (!Clang->hasTarget()) { Clang->setInvocation(nullptr); return; } // Inform the target of the language options. // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. Clang->getTarget().adjust(Clang->getLangOpts()); assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == InputKind::Source && "FIXME: AST inputs not yet supported here!"); assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != InputKind::LLVM_IR && "IR inputs not support here!"); // Use the source and file managers that we were given. Clang->setFileManager(&FileMgr); Clang->setSourceManager(&SourceMgr); // Remap files. PreprocessorOpts.clearRemappedFiles(); PreprocessorOpts.RetainRemappedFileBuffers = true; for (const auto &RemappedFile : RemappedFiles) { PreprocessorOpts.addRemappedFile(RemappedFile.first, RemappedFile.second); OwnedBuffers.push_back(RemappedFile.second); } // Use the code completion consumer we were given, but adding any cached // code-completion results. AugmentedCodeCompleteConsumer *AugmentedConsumer = new AugmentedCodeCompleteConsumer(*this, Consumer, CodeCompleteOpts); Clang->setCodeCompletionConsumer(AugmentedConsumer); // If we have a precompiled preamble, try to use it. We only allow // the use of the precompiled preamble if we're if the completion // point is within the main file, after the end of the precompiled // preamble. std::unique_ptr OverrideMainBuffer; if (!getPreambleFile(this).empty()) { std::string CompleteFilePath(File); llvm::sys::fs::UniqueID CompleteFileID; if (!llvm::sys::fs::getUniqueID(CompleteFilePath, CompleteFileID)) { std::string MainPath(OriginalSourceFile); llvm::sys::fs::UniqueID MainID; if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) { if (CompleteFileID == MainID && Line > 1) OverrideMainBuffer = getMainBufferWithPrecompiledPreamble( PCHContainerOps, Inv, false, Line - 1); } } } // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer.get()); PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this); PreprocessorOpts.DisablePCHValidation = true; OwnedBuffers.push_back(OverrideMainBuffer.release()); } else { PreprocessorOpts.PrecompiledPreambleBytes.first = 0; PreprocessorOpts.PrecompiledPreambleBytes.second = false; } // Disable the preprocessing record if modules are not enabled. if (!Clang->getLangOpts().Modules) PreprocessorOpts.DetailedRecord = false; std::unique_ptr Act; Act.reset(new SyntaxOnlyAction); if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { Act->Execute(); Act->EndSourceFile(); } } bool ASTUnit::Save(StringRef File) { if (HadModuleLoaderFatalFailure) return true; // Write to a temporary file and later rename it to the actual file, to avoid // possible race conditions. SmallString<128> TempPath; TempPath = File; TempPath += "-%%%%%%%%"; int fd; if (llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath)) return true; // FIXME: Can we somehow regenerate the stat cache here, or do we need to // unconditionally create a stat cache when we parse the file? llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true); serialize(Out); Out.close(); if (Out.has_error()) { Out.clear_error(); return true; } if (llvm::sys::fs::rename(TempPath, File)) { llvm::sys::fs::remove(TempPath); return true; } return false; } static bool serializeUnit(ASTWriter &Writer, SmallVectorImpl &Buffer, Sema &S, bool hasErrors, raw_ostream &OS) { Writer.WriteAST(S, std::string(), nullptr, "", hasErrors); // Write the generated bitstream to "Out". if (!Buffer.empty()) OS.write(Buffer.data(), Buffer.size()); return false; } bool ASTUnit::serialize(raw_ostream &OS) { // For serialization we are lenient if the errors were only warn-as-error kind. bool hasErrors = getDiagnostics().hasUncompilableErrorOccurred(); if (WriterData) return serializeUnit(WriterData->Writer, WriterData->Buffer, getSema(), hasErrors, OS); SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); MemoryBufferCache PCMCache; ASTWriter Writer(Stream, Buffer, PCMCache, {}); return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS); } typedef ContinuousRangeMap SLocRemap; void ASTUnit::TranslateStoredDiagnostics( FileManager &FileMgr, SourceManager &SrcMgr, const SmallVectorImpl &Diags, SmallVectorImpl &Out) { // Map the standalone diagnostic into the new source manager. We also need to // remap all the locations to the new view. This includes the diag location, // any associated source ranges, and the source ranges of associated fix-its. // FIXME: There should be a cleaner way to do this. SmallVector Result; Result.reserve(Diags.size()); const FileEntry *PreviousFE = nullptr; FileID FID; for (const StandaloneDiagnostic &SD : Diags) { // Rebuild the StoredDiagnostic. if (SD.Filename.empty()) continue; const FileEntry *FE = FileMgr.getFile(SD.Filename); if (!FE) continue; if (FE != PreviousFE) { FID = SrcMgr.translateFile(FE); PreviousFE = FE; } SourceLocation FileLoc = SrcMgr.getLocForStartOfFile(FID); if (FileLoc.isInvalid()) continue; SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset); FullSourceLoc Loc(L, SrcMgr); SmallVector Ranges; Ranges.reserve(SD.Ranges.size()); for (const auto &Range : SD.Ranges) { SourceLocation BL = FileLoc.getLocWithOffset(Range.first); SourceLocation EL = FileLoc.getLocWithOffset(Range.second); Ranges.push_back(CharSourceRange::getCharRange(BL, EL)); } SmallVector FixIts; FixIts.reserve(SD.FixIts.size()); for (const StandaloneFixIt &FixIt : SD.FixIts) { FixIts.push_back(FixItHint()); FixItHint &FH = FixIts.back(); FH.CodeToInsert = FixIt.CodeToInsert; SourceLocation BL = FileLoc.getLocWithOffset(FixIt.RemoveRange.first); SourceLocation EL = FileLoc.getLocWithOffset(FixIt.RemoveRange.second); FH.RemoveRange = CharSourceRange::getCharRange(BL, EL); } Result.push_back(StoredDiagnostic(SD.Level, SD.ID, SD.Message, Loc, Ranges, FixIts)); } Result.swap(Out); } void ASTUnit::addFileLevelDecl(Decl *D) { assert(D); // We only care about local declarations. if (D->isFromASTFile()) return; SourceManager &SM = *SourceMgr; SourceLocation Loc = D->getLocation(); if (Loc.isInvalid() || !SM.isLocalSourceLocation(Loc)) return; // We only keep track of the file-level declarations of each file. if (!D->getLexicalDeclContext()->isFileContext()) return; SourceLocation FileLoc = SM.getFileLoc(Loc); assert(SM.isLocalSourceLocation(FileLoc)); FileID FID; unsigned Offset; std::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc); if (FID.isInvalid()) return; LocDeclsTy *&Decls = FileDecls[FID]; if (!Decls) Decls = new LocDeclsTy(); std::pair LocDecl(Offset, D); if (Decls->empty() || Decls->back().first <= Offset) { Decls->push_back(LocDecl); return; } LocDeclsTy::iterator I = std::upper_bound(Decls->begin(), Decls->end(), LocDecl, llvm::less_first()); Decls->insert(I, LocDecl); } void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length, SmallVectorImpl &Decls) { if (File.isInvalid()) return; if (SourceMgr->isLoadedFileID(File)) { assert(Ctx->getExternalSource() && "No external source!"); return Ctx->getExternalSource()->FindFileRegionDecls(File, Offset, Length, Decls); } FileDeclsTy::iterator I = FileDecls.find(File); if (I == FileDecls.end()) return; LocDeclsTy &LocDecls = *I->second; if (LocDecls.empty()) return; LocDeclsTy::iterator BeginIt = std::lower_bound(LocDecls.begin(), LocDecls.end(), std::make_pair(Offset, (Decl *)nullptr), llvm::less_first()); if (BeginIt != LocDecls.begin()) --BeginIt; // If we are pointing at a top-level decl inside an objc container, we need // to backtrack until we find it otherwise we will fail to report that the // region overlaps with an objc container. while (BeginIt != LocDecls.begin() && BeginIt->second->isTopLevelDeclInObjCContainer()) --BeginIt; LocDeclsTy::iterator EndIt = std::upper_bound( LocDecls.begin(), LocDecls.end(), std::make_pair(Offset + Length, (Decl *)nullptr), llvm::less_first()); if (EndIt != LocDecls.end()) ++EndIt; for (LocDeclsTy::iterator DIt = BeginIt; DIt != EndIt; ++DIt) Decls.push_back(DIt->second); } SourceLocation ASTUnit::getLocation(const FileEntry *File, unsigned Line, unsigned Col) const { const SourceManager &SM = getSourceManager(); SourceLocation Loc = SM.translateFileLineCol(File, Line, Col); return SM.getMacroArgExpandedLocation(Loc); } SourceLocation ASTUnit::getLocation(const FileEntry *File, unsigned Offset) const { const SourceManager &SM = getSourceManager(); SourceLocation FileLoc = SM.translateFileLineCol(File, 1, 1); return SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset)); } /// \brief If \arg Loc is a loaded location from the preamble, returns /// the corresponding local location of the main file, otherwise it returns /// \arg Loc. SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) { FileID PreambleID; if (SourceMgr) PreambleID = SourceMgr->getPreambleFileID(); if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) return Loc; unsigned Offs; if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) { SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()); return FileLoc.getLocWithOffset(Offs); } return Loc; } /// \brief If \arg Loc is a local location of the main file but inside the /// preamble chunk, returns the corresponding loaded location from the /// preamble, otherwise it returns \arg Loc. SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) { FileID PreambleID; if (SourceMgr) PreambleID = SourceMgr->getPreambleFileID(); if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) return Loc; unsigned Offs; if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) && Offs < Preamble.size()) { SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID); return FileLoc.getLocWithOffset(Offs); } return Loc; } bool ASTUnit::isInPreambleFileID(SourceLocation Loc) { FileID FID; if (SourceMgr) FID = SourceMgr->getPreambleFileID(); if (Loc.isInvalid() || FID.isInvalid()) return false; return SourceMgr->isInFileID(Loc, FID); } bool ASTUnit::isInMainFileID(SourceLocation Loc) { FileID FID; if (SourceMgr) FID = SourceMgr->getMainFileID(); if (Loc.isInvalid() || FID.isInvalid()) return false; return SourceMgr->isInFileID(Loc, FID); } SourceLocation ASTUnit::getEndOfPreambleFileID() { FileID FID; if (SourceMgr) FID = SourceMgr->getPreambleFileID(); if (FID.isInvalid()) return SourceLocation(); return SourceMgr->getLocForEndOfFile(FID); } SourceLocation ASTUnit::getStartOfMainFileID() { FileID FID; if (SourceMgr) FID = SourceMgr->getMainFileID(); if (FID.isInvalid()) return SourceLocation(); return SourceMgr->getLocForStartOfFile(FID); } llvm::iterator_range ASTUnit::getLocalPreprocessingEntities() const { if (isMainFileAST()) { serialization::ModuleFile & Mod = Reader->getModuleManager().getPrimaryModule(); return Reader->getModulePreprocessedEntities(Mod); } if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) return llvm::make_range(PPRec->local_begin(), PPRec->local_end()); return llvm::make_range(PreprocessingRecord::iterator(), PreprocessingRecord::iterator()); } bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) { if (isMainFileAST()) { serialization::ModuleFile & Mod = Reader->getModuleManager().getPrimaryModule(); for (const Decl *D : Reader->getModuleFileLevelDecls(Mod)) { if (!Fn(context, D)) return false; } return true; } for (ASTUnit::top_level_iterator TL = top_level_begin(), TLEnd = top_level_end(); TL != TLEnd; ++TL) { if (!Fn(context, *TL)) return false; } return true; } const FileEntry *ASTUnit::getPCHFile() { if (!Reader) return nullptr; serialization::ModuleFile *Mod = nullptr; Reader->getModuleManager().visit([&Mod](serialization::ModuleFile &M) { switch (M.Kind) { case serialization::MK_ImplicitModule: case serialization::MK_ExplicitModule: case serialization::MK_PrebuiltModule: return true; // skip dependencies. case serialization::MK_PCH: Mod = &M; return true; // found it. case serialization::MK_Preamble: return false; // look in dependencies. case serialization::MK_MainFile: return false; // look in dependencies. } return true; }); if (Mod) return Mod->File; return nullptr; } bool ASTUnit::isModuleFile() { return isMainFileAST() && ASTFileLangOpts.isCompilingModule(); } void ASTUnit::PreambleData::countLines() const { NumLines = 0; if (empty()) return; NumLines = std::count(Buffer.begin(), Buffer.end(), '\n'); if (Buffer.back() != '\n') ++NumLines; } #ifndef NDEBUG ASTUnit::ConcurrencyState::ConcurrencyState() { Mutex = new llvm::sys::MutexImpl(/*recursive=*/true); } ASTUnit::ConcurrencyState::~ConcurrencyState() { delete static_cast(Mutex); } void ASTUnit::ConcurrencyState::start() { bool acquired = static_cast(Mutex)->tryacquire(); assert(acquired && "Concurrent access to ASTUnit!"); } void ASTUnit::ConcurrencyState::finish() { static_cast(Mutex)->release(); } #else // NDEBUG ASTUnit::ConcurrencyState::ConcurrencyState() { Mutex = nullptr; } ASTUnit::ConcurrencyState::~ConcurrencyState() {} void ASTUnit::ConcurrencyState::start() {} void ASTUnit::ConcurrencyState::finish() {} #endif // NDEBUG Index: vendor/clang/dist/lib/Headers/xmmintrin.h =================================================================== --- vendor/clang/dist/lib/Headers/xmmintrin.h (revision 318415) +++ vendor/clang/dist/lib/Headers/xmmintrin.h (revision 318416) @@ -1,2976 +1,2969 @@ /*===---- xmmintrin.h - SSE intrinsics -------------------------------------=== * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * *===-----------------------------------------------------------------------=== */ #ifndef __XMMINTRIN_H #define __XMMINTRIN_H #include typedef int __v4si __attribute__((__vector_size__(16))); typedef float __v4sf __attribute__((__vector_size__(16))); typedef float __m128 __attribute__((__vector_size__(16))); /* Unsigned types */ typedef unsigned int __v4su __attribute__((__vector_size__(16))); /* This header should only be included in a hosted environment as it depends on * a standard library to provide allocation routines. */ #if __STDC_HOSTED__ #include #endif /* Define the default attributes for the functions in this file. */ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("sse"))) /// \brief Adds the 32-bit float values in the low-order bits of the operands. /// /// \headerfile /// /// This intrinsic corresponds to the VADDSS / ADDSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the source operands. /// The lower 32 bits of this operand are used in the calculation. /// \param __b /// A 128-bit vector of [4 x float] containing one of the source operands. /// The lower 32 bits of this operand are used in the calculation. /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the sum /// of the lower 32 bits of both operands. The upper 96 bits are copied from /// the upper 96 bits of the first source operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_add_ss(__m128 __a, __m128 __b) { __a[0] += __b[0]; return __a; } /// \brief Adds two 128-bit vectors of [4 x float], and returns the results of /// the addition. /// /// \headerfile /// /// This intrinsic corresponds to the VADDPS / ADDPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the source operands. /// \param __b /// A 128-bit vector of [4 x float] containing one of the source operands. /// \returns A 128-bit vector of [4 x float] containing the sums of both /// operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_add_ps(__m128 __a, __m128 __b) { return (__m128)((__v4sf)__a + (__v4sf)__b); } /// \brief Subtracts the 32-bit float value in the low-order bits of the second /// operand from the corresponding value in the first operand. /// /// \headerfile /// /// This intrinsic corresponds to the VSUBSS / SUBSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing the minuend. The lower 32 bits /// of this operand are used in the calculation. /// \param __b /// A 128-bit vector of [4 x float] containing the subtrahend. The lower 32 /// bits of this operand are used in the calculation. /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// difference of the lower 32 bits of both operands. The upper 96 bits are /// copied from the upper 96 bits of the first source operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_sub_ss(__m128 __a, __m128 __b) { __a[0] -= __b[0]; return __a; } /// \brief Subtracts each of the values of the second operand from the first /// operand, both of which are 128-bit vectors of [4 x float] and returns /// the results of the subtraction. /// /// \headerfile /// /// This intrinsic corresponds to the VSUBPS / SUBPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing the minuend. /// \param __b /// A 128-bit vector of [4 x float] containing the subtrahend. /// \returns A 128-bit vector of [4 x float] containing the differences between /// both operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_sub_ps(__m128 __a, __m128 __b) { return (__m128)((__v4sf)__a - (__v4sf)__b); } /// \brief Multiplies two 32-bit float values in the low-order bits of the /// operands. /// /// \headerfile /// /// This intrinsic corresponds to the VMULSS / MULSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the source operands. /// The lower 32 bits of this operand are used in the calculation. /// \param __b /// A 128-bit vector of [4 x float] containing one of the source operands. /// The lower 32 bits of this operand are used in the calculation. /// \returns A 128-bit vector of [4 x float] containing the product of the lower /// 32 bits of both operands. The upper 96 bits are copied from the upper 96 /// bits of the first source operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_mul_ss(__m128 __a, __m128 __b) { __a[0] *= __b[0]; return __a; } /// \brief Multiplies two 128-bit vectors of [4 x float] and returns the /// results of the multiplication. /// /// \headerfile /// /// This intrinsic corresponds to the VMULPS / MULPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the source operands. /// \param __b /// A 128-bit vector of [4 x float] containing one of the source operands. /// \returns A 128-bit vector of [4 x float] containing the products of both /// operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_mul_ps(__m128 __a, __m128 __b) { return (__m128)((__v4sf)__a * (__v4sf)__b); } /// \brief Divides the value in the low-order 32 bits of the first operand by /// the corresponding value in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VDIVSS / DIVSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing the dividend. The lower 32 /// bits of this operand are used in the calculation. /// \param __b /// A 128-bit vector of [4 x float] containing the divisor. The lower 32 bits /// of this operand are used in the calculation. /// \returns A 128-bit vector of [4 x float] containing the quotients of the /// lower 32 bits of both operands. The upper 96 bits are copied from the /// upper 96 bits of the first source operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_div_ss(__m128 __a, __m128 __b) { __a[0] /= __b[0]; return __a; } /// \brief Divides two 128-bit vectors of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VDIVPS / DIVPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing the dividend. /// \param __b /// A 128-bit vector of [4 x float] containing the divisor. /// \returns A 128-bit vector of [4 x float] containing the quotients of both /// operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_div_ps(__m128 __a, __m128 __b) { return (__m128)((__v4sf)__a / (__v4sf)__b); } /// \brief Calculates the square root of the value stored in the low-order bits /// of a 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VSQRTSS / SQRTSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the calculation. /// \returns A 128-bit vector of [4 x float] containing the square root of the /// value in the low-order bits of the operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_sqrt_ss(__m128 __a) { __m128 __c = __builtin_ia32_sqrtss((__v4sf)__a); return (__m128) { __c[0], __a[1], __a[2], __a[3] }; } /// \brief Calculates the square roots of the values stored in a 128-bit vector /// of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VSQRTPS / SQRTPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the square roots of the /// values in the operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_sqrt_ps(__m128 __a) { return __builtin_ia32_sqrtps((__v4sf)__a); } /// \brief Calculates the approximate reciprocal of the value stored in the /// low-order bits of a 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VRCPSS / RCPSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the calculation. /// \returns A 128-bit vector of [4 x float] containing the approximate /// reciprocal of the value in the low-order bits of the operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_rcp_ss(__m128 __a) { __m128 __c = __builtin_ia32_rcpss((__v4sf)__a); return (__m128) { __c[0], __a[1], __a[2], __a[3] }; } /// \brief Calculates the approximate reciprocals of the values stored in a /// 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VRCPPS / RCPPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the approximate /// reciprocals of the values in the operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_rcp_ps(__m128 __a) { return __builtin_ia32_rcpps((__v4sf)__a); } /// \brief Calculates the approximate reciprocal of the square root of the value /// stored in the low-order bits of a 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VRSQRTSS / RSQRTSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the calculation. /// \returns A 128-bit vector of [4 x float] containing the approximate /// reciprocal of the square root of the value in the low-order bits of the /// operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_rsqrt_ss(__m128 __a) { __m128 __c = __builtin_ia32_rsqrtss((__v4sf)__a); return (__m128) { __c[0], __a[1], __a[2], __a[3] }; } /// \brief Calculates the approximate reciprocals of the square roots of the /// values stored in a 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VRSQRTPS / RSQRTPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the approximate /// reciprocals of the square roots of the values in the operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_rsqrt_ps(__m128 __a) { return __builtin_ia32_rsqrtps((__v4sf)__a); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands and returns the lesser value in the low-order bits of the /// vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VMINSS / MINSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// minimum value between both operands. The upper 96 bits are copied from /// the upper 96 bits of the first source operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_min_ss(__m128 __a, __m128 __b) { return __builtin_ia32_minss((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 128-bit vectors of [4 x float] and returns the lesser /// of each pair of values. /// /// \headerfile /// /// This intrinsic corresponds to the VMINPS / MINPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. /// \returns A 128-bit vector of [4 x float] containing the minimum values /// between both operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_min_ps(__m128 __a, __m128 __b) { return __builtin_ia32_minps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands and returns the greater value in the low-order bits of a 128-bit /// vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VMAXSS / MAXSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// maximum value between both operands. The upper 96 bits are copied from /// the upper 96 bits of the first source operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_max_ss(__m128 __a, __m128 __b) { return __builtin_ia32_maxss((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 128-bit vectors of [4 x float] and returns the greater /// of each pair of values. /// /// \headerfile /// /// This intrinsic corresponds to the VMAXPS / MAXPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. /// \returns A 128-bit vector of [4 x float] containing the maximum values /// between both operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_max_ps(__m128 __a, __m128 __b) { return __builtin_ia32_maxps((__v4sf)__a, (__v4sf)__b); } /// \brief Performs a bitwise AND of two 128-bit vectors of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VANDPS / ANDPS instructions. /// /// \param __a /// A 128-bit vector containing one of the source operands. /// \param __b /// A 128-bit vector containing one of the source operands. /// \returns A 128-bit vector of [4 x float] containing the bitwise AND of the /// values between both operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_and_ps(__m128 __a, __m128 __b) { return (__m128)((__v4su)__a & (__v4su)__b); } /// \brief Performs a bitwise AND of two 128-bit vectors of [4 x float], using /// the one's complement of the values contained in the first source /// operand. /// /// \headerfile /// /// This intrinsic corresponds to the VANDNPS / ANDNPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing the first source operand. The /// one's complement of this value is used in the bitwise AND. /// \param __b /// A 128-bit vector of [4 x float] containing the second source operand. /// \returns A 128-bit vector of [4 x float] containing the bitwise AND of the /// one's complement of the first operand and the values in the second /// operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_andnot_ps(__m128 __a, __m128 __b) { return (__m128)(~(__v4su)__a & (__v4su)__b); } /// \brief Performs a bitwise OR of two 128-bit vectors of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VORPS / ORPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the source operands. /// \param __b /// A 128-bit vector of [4 x float] containing one of the source operands. /// \returns A 128-bit vector of [4 x float] containing the bitwise OR of the /// values between both operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_or_ps(__m128 __a, __m128 __b) { return (__m128)((__v4su)__a | (__v4su)__b); } /// \brief Performs a bitwise exclusive OR of two 128-bit vectors of /// [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VXORPS / XORPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the source operands. /// \param __b /// A 128-bit vector of [4 x float] containing one of the source operands. /// \returns A 128-bit vector of [4 x float] containing the bitwise exclusive OR /// of the values between both operands. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_xor_ps(__m128 __a, __m128 __b) { return (__m128)((__v4su)__a ^ (__v4su)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands for equality and returns the result of the comparison in the /// low-order bits of a vector [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPEQSS / CMPEQSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpeq_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpeqss((__v4sf)__a, (__v4sf)__b); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] for equality. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPEQPS / CMPEQPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpeq_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpeqps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is less than the /// corresponding value in the second operand and returns the result of the /// comparison in the low-order bits of a vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPLTSS / CMPLTSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmplt_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpltss((__v4sf)__a, (__v4sf)__b); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are less than those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPLTPS / CMPLTPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmplt_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpltps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is less than or /// equal to the corresponding value in the second operand and returns the /// result of the comparison in the low-order bits of a vector of /// [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPLESS / CMPLESS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmple_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpless((__v4sf)__a, (__v4sf)__b); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are less than or equal to those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPLEPS / CMPLEPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmple_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpleps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is greater than /// the corresponding value in the second operand and returns the result of /// the comparison in the low-order bits of a vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPLTSS / CMPLTSS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpgt_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_shufflevector((__v4sf)__a, (__v4sf)__builtin_ia32_cmpltss((__v4sf)__b, (__v4sf)__a), 4, 1, 2, 3); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are greater than those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPLTPS / CMPLTPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpgt_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpltps((__v4sf)__b, (__v4sf)__a); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is greater than /// or equal to the corresponding value in the second operand and returns /// the result of the comparison in the low-order bits of a vector of /// [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPLESS / CMPLESS instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpge_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_shufflevector((__v4sf)__a, (__v4sf)__builtin_ia32_cmpless((__v4sf)__b, (__v4sf)__a), 4, 1, 2, 3); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are greater than or equal to those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPLEPS / CMPLEPS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpge_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpleps((__v4sf)__b, (__v4sf)__a); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands for inequality and returns the result of the comparison in the /// low-order bits of a vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNEQSS / CMPNEQSS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpneq_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpneqss((__v4sf)__a, (__v4sf)__b); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] for inequality. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNEQPS / CMPNEQPS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpneq_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpneqps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is not less than /// the corresponding value in the second operand and returns the result of /// the comparison in the low-order bits of a vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNLTSS / CMPNLTSS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpnlt_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpnltss((__v4sf)__a, (__v4sf)__b); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are not less than those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNLTPS / CMPNLTPS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpnlt_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpnltps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is not less than /// or equal to the corresponding value in the second operand and returns /// the result of the comparison in the low-order bits of a vector of /// [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNLESS / CMPNLESS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpnle_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpnless((__v4sf)__a, (__v4sf)__b); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are not less than or equal to those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNLEPS / CMPNLEPS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpnle_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpnleps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is not greater /// than the corresponding value in the second operand and returns the /// result of the comparison in the low-order bits of a vector of /// [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNLTSS / CMPNLTSS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpngt_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_shufflevector((__v4sf)__a, (__v4sf)__builtin_ia32_cmpnltss((__v4sf)__b, (__v4sf)__a), 4, 1, 2, 3); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are not greater than those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNLTPS / CMPNLTPS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpngt_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpnltps((__v4sf)__b, (__v4sf)__a); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is not greater /// than or equal to the corresponding value in the second operand and /// returns the result of the comparison in the low-order bits of a vector /// of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNLESS / CMPNLESS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpnge_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_shufflevector((__v4sf)__a, (__v4sf)__builtin_ia32_cmpnless((__v4sf)__b, (__v4sf)__a), 4, 1, 2, 3); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are not greater than or equal to those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPNLEPS / CMPNLEPS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpnge_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpnleps((__v4sf)__b, (__v4sf)__a); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is ordered with /// respect to the corresponding value in the second operand and returns the /// result of the comparison in the low-order bits of a vector of /// [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPORDSS / CMPORDSS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpord_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpordss((__v4sf)__a, (__v4sf)__b); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are ordered with respect to those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPORDPS / CMPORDPS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpord_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpordps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the value in the first operand is unordered /// with respect to the corresponding value in the second operand and /// returns the result of the comparison in the low-order bits of a vector /// of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPUNORDSS / CMPUNORDSS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \param __b /// A 128-bit vector of [4 x float] containing one of the operands. The lower /// 32 bits of this operand are used in the comparison. /// \returns A 128-bit vector of [4 x float] containing the comparison results /// in the low-order bits. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpunord_ss(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpunordss((__v4sf)__a, (__v4sf)__b); } /// \brief Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are unordered with respect to those in the second operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCMPUNORDPS / CMPUNORDPS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 128-bit vector of [4 x float]. /// \returns A 128-bit vector of [4 x float] containing the comparison results. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cmpunord_ps(__m128 __a, __m128 __b) { return (__m128)__builtin_ia32_cmpunordps((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands for equality and returns the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VCOMISS / COMISS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_comieq_ss(__m128 __a, __m128 __b) { return __builtin_ia32_comieq((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the first operand is less than the second /// operand and returns the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VCOMISS / COMISS /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_comilt_ss(__m128 __a, __m128 __b) { return __builtin_ia32_comilt((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the first operand is less than or equal to the /// second operand and returns the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VCOMISS / COMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_comile_ss(__m128 __a, __m128 __b) { return __builtin_ia32_comile((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the first operand is greater than the second /// operand and returns the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VCOMISS / COMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_comigt_ss(__m128 __a, __m128 __b) { return __builtin_ia32_comigt((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the first operand is greater than or equal to /// the second operand and returns the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VCOMISS / COMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_comige_ss(__m128 __a, __m128 __b) { return __builtin_ia32_comige((__v4sf)__a, (__v4sf)__b); } /// \brief Compares two 32-bit float values in the low-order bits of both /// operands to determine if the first operand is not equal to the second /// operand and returns the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VCOMISS / COMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_comineq_ss(__m128 __a, __m128 __b) { return __builtin_ia32_comineq((__v4sf)__a, (__v4sf)__b); } /// \brief Performs an unordered comparison of two 32-bit float values using /// the low-order bits of both operands to determine equality and returns /// the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VUCOMISS / UCOMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_ucomieq_ss(__m128 __a, __m128 __b) { return __builtin_ia32_ucomieq((__v4sf)__a, (__v4sf)__b); } /// \brief Performs an unordered comparison of two 32-bit float values using /// the low-order bits of both operands to determine if the first operand is /// less than the second operand and returns the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VUCOMISS / UCOMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_ucomilt_ss(__m128 __a, __m128 __b) { return __builtin_ia32_ucomilt((__v4sf)__a, (__v4sf)__b); } /// \brief Performs an unordered comparison of two 32-bit float values using /// the low-order bits of both operands to determine if the first operand is /// less than or equal to the second operand and returns the result of the /// comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VUCOMISS / UCOMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_ucomile_ss(__m128 __a, __m128 __b) { return __builtin_ia32_ucomile((__v4sf)__a, (__v4sf)__b); } /// \brief Performs an unordered comparison of two 32-bit float values using /// the low-order bits of both operands to determine if the first operand is /// greater than the second operand and returns the result of the /// comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VUCOMISS / UCOMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_ucomigt_ss(__m128 __a, __m128 __b) { return __builtin_ia32_ucomigt((__v4sf)__a, (__v4sf)__b); } /// \brief Performs an unordered comparison of two 32-bit float values using /// the low-order bits of both operands to determine if the first operand is /// greater than or equal to the second operand and returns the result of /// the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VUCOMISS / UCOMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_ucomige_ss(__m128 __a, __m128 __b) { return __builtin_ia32_ucomige((__v4sf)__a, (__v4sf)__b); } /// \brief Performs an unordered comparison of two 32-bit float values using /// the low-order bits of both operands to determine inequality and returns /// the result of the comparison. /// /// \headerfile /// /// This intrinsic corresponds to the VUCOMISS / UCOMISS instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \param __b /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the comparison. /// \returns An integer containing the comparison results. static __inline__ int __DEFAULT_FN_ATTRS _mm_ucomineq_ss(__m128 __a, __m128 __b) { return __builtin_ia32_ucomineq((__v4sf)__a, (__v4sf)__b); } /// \brief Converts a float value contained in the lower 32 bits of a vector of /// [4 x float] into a 32-bit integer. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTSS2SI / CVTSS2SI /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the conversion. /// \returns A 32-bit integer containing the converted value. static __inline__ int __DEFAULT_FN_ATTRS _mm_cvtss_si32(__m128 __a) { return __builtin_ia32_cvtss2si((__v4sf)__a); } /// \brief Converts a float value contained in the lower 32 bits of a vector of /// [4 x float] into a 32-bit integer. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTSS2SI / CVTSS2SI /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the conversion. /// \returns A 32-bit integer containing the converted value. static __inline__ int __DEFAULT_FN_ATTRS _mm_cvt_ss2si(__m128 __a) { return _mm_cvtss_si32(__a); } #ifdef __x86_64__ /// \brief Converts a float value contained in the lower 32 bits of a vector of /// [4 x float] into a 64-bit integer. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTSS2SI / CVTSS2SI /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the conversion. /// \returns A 64-bit integer containing the converted value. static __inline__ long long __DEFAULT_FN_ATTRS _mm_cvtss_si64(__m128 __a) { return __builtin_ia32_cvtss2si64((__v4sf)__a); } #endif /// \brief Converts two low-order float values in a 128-bit vector of /// [4 x float] into a 64-bit vector of [2 x i32]. /// /// \headerfile /// /// This intrinsic corresponds to the CVTPS2PI instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \returns A 64-bit integer vector containing the converted values. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvtps_pi32(__m128 __a) { return (__m64)__builtin_ia32_cvtps2pi((__v4sf)__a); } /// \brief Converts two low-order float values in a 128-bit vector of /// [4 x float] into a 64-bit vector of [2 x i32]. /// /// \headerfile /// /// This intrinsic corresponds to the CVTPS2PI instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \returns A 64-bit integer vector containing the converted values. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvt_ps2pi(__m128 __a) { return _mm_cvtps_pi32(__a); } /// \brief Converts a float value contained in the lower 32 bits of a vector of /// [4 x float] into a 32-bit integer, truncating the result when it is /// inexact. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTTSS2SI / CVTTSS2SI /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the conversion. /// \returns A 32-bit integer containing the converted value. static __inline__ int __DEFAULT_FN_ATTRS _mm_cvttss_si32(__m128 __a) { return __builtin_ia32_cvttss2si((__v4sf)__a); } /// \brief Converts a float value contained in the lower 32 bits of a vector of /// [4 x float] into a 32-bit integer, truncating the result when it is /// inexact. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTTSS2SI / CVTTSS2SI /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the conversion. /// \returns A 32-bit integer containing the converted value. static __inline__ int __DEFAULT_FN_ATTRS _mm_cvtt_ss2si(__m128 __a) { return _mm_cvttss_si32(__a); } #ifdef __x86_64__ /// \brief Converts a float value contained in the lower 32 bits of a vector of /// [4 x float] into a 64-bit integer, truncating the result when it is /// inexact. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTTSS2SI / CVTTSS2SI /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the conversion. /// \returns A 64-bit integer containing the converted value. static __inline__ long long __DEFAULT_FN_ATTRS _mm_cvttss_si64(__m128 __a) { return __builtin_ia32_cvttss2si64((__v4sf)__a); } #endif /// \brief Converts two low-order float values in a 128-bit vector of /// [4 x float] into a 64-bit vector of [2 x i32], truncating the result /// when it is inexact. /// /// \headerfile /// /// This intrinsic corresponds to the CVTTPS2PI / VTTPS2PI /// instructions. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \returns A 64-bit integer vector containing the converted values. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvttps_pi32(__m128 __a) { return (__m64)__builtin_ia32_cvttps2pi((__v4sf)__a); } /// \brief Converts two low-order float values in a 128-bit vector of [4 x /// float] into a 64-bit vector of [2 x i32], truncating the result when it /// is inexact. /// /// \headerfile /// /// This intrinsic corresponds to the CVTTPS2PI instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \returns A 64-bit integer vector containing the converted values. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvtt_ps2pi(__m128 __a) { return _mm_cvttps_pi32(__a); } /// \brief Converts a 32-bit signed integer value into a floating point value /// and writes it to the lower 32 bits of the destination. The remaining /// higher order elements of the destination vector are copied from the /// corresponding elements in the first operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTSI2SS / CVTSI2SS instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 32-bit signed integer operand containing the value to be converted. /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// converted value of the second operand. The upper 96 bits are copied from /// the upper 96 bits of the first operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtsi32_ss(__m128 __a, int __b) { __a[0] = __b; return __a; } /// \brief Converts a 32-bit signed integer value into a floating point value /// and writes it to the lower 32 bits of the destination. The remaining /// higher order elements of the destination are copied from the /// corresponding elements in the first operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTSI2SS / CVTSI2SS instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 32-bit signed integer operand containing the value to be converted. /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// converted value of the second operand. The upper 96 bits are copied from /// the upper 96 bits of the first operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvt_si2ss(__m128 __a, int __b) { return _mm_cvtsi32_ss(__a, __b); } #ifdef __x86_64__ /// \brief Converts a 64-bit signed integer value into a floating point value /// and writes it to the lower 32 bits of the destination. The remaining /// higher order elements of the destination are copied from the /// corresponding elements in the first operand. /// /// \headerfile /// /// This intrinsic corresponds to the VCVTSI2SS / CVTSI2SS instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 64-bit signed integer operand containing the value to be converted. /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// converted value of the second operand. The upper 96 bits are copied from /// the upper 96 bits of the first operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtsi64_ss(__m128 __a, long long __b) { __a[0] = __b; return __a; } #endif /// \brief Converts two elements of a 64-bit vector of [2 x i32] into two /// floating point values and writes them to the lower 64-bits of the /// destination. The remaining higher order elements of the destination are /// copied from the corresponding elements in the first operand. /// /// \headerfile /// /// This intrinsic corresponds to the CVTPI2PS instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 64-bit vector of [2 x i32]. The elements in this vector are converted /// and written to the corresponding low-order elements in the destination. /// \returns A 128-bit vector of [4 x float] whose lower 64 bits contain the /// converted value of the second operand. The upper 64 bits are copied from /// the upper 64 bits of the first operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtpi32_ps(__m128 __a, __m64 __b) { return __builtin_ia32_cvtpi2ps((__v4sf)__a, (__v2si)__b); } /// \brief Converts two elements of a 64-bit vector of [2 x i32] into two /// floating point values and writes them to the lower 64-bits of the /// destination. The remaining higher order elements of the destination are /// copied from the corresponding elements in the first operand. /// /// \headerfile /// /// This intrinsic corresponds to the CVTPI2PS instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. /// \param __b /// A 64-bit vector of [2 x i32]. The elements in this vector are converted /// and written to the corresponding low-order elements in the destination. /// \returns A 128-bit vector of [4 x float] whose lower 64 bits contain the /// converted value from the second operand. The upper 64 bits are copied /// from the upper 64 bits of the first operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvt_pi2ps(__m128 __a, __m64 __b) { return _mm_cvtpi32_ps(__a, __b); } /// \brief Extracts a float value contained in the lower 32 bits of a vector of /// [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVSS / MOVSS instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. The lower 32 bits of this operand are /// used in the extraction. /// \returns A 32-bit float containing the extracted value. static __inline__ float __DEFAULT_FN_ATTRS _mm_cvtss_f32(__m128 __a) { return __a[0]; } /// \brief Loads two packed float values from the address \a __p into the /// high-order bits of a 128-bit vector of [4 x float]. The low-order bits /// are copied from the low-order bits of the first operand. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVHPD / MOVHPD instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. Bits [63:0] are written to bits [63:0] /// of the destination. /// \param __p /// A pointer to two packed float values. Bits [63:0] are written to bits /// [127:64] of the destination. /// \returns A 128-bit vector of [4 x float] containing the moved values. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_loadh_pi(__m128 __a, const __m64 *__p) { typedef float __mm_loadh_pi_v2f32 __attribute__((__vector_size__(8))); struct __mm_loadh_pi_struct { __mm_loadh_pi_v2f32 __u; } __attribute__((__packed__, __may_alias__)); __mm_loadh_pi_v2f32 __b = ((struct __mm_loadh_pi_struct*)__p)->__u; __m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1); return __builtin_shufflevector(__a, __bb, 0, 1, 4, 5); } /// \brief Loads two packed float values from the address \a __p into the /// low-order bits of a 128-bit vector of [4 x float]. The high-order bits /// are copied from the high-order bits of the first operand. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVLPD / MOVLPD instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. Bits [127:64] are written to bits /// [127:64] of the destination. /// \param __p /// A pointer to two packed float values. Bits [63:0] are written to bits /// [63:0] of the destination. /// \returns A 128-bit vector of [4 x float] containing the moved values. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_loadl_pi(__m128 __a, const __m64 *__p) { typedef float __mm_loadl_pi_v2f32 __attribute__((__vector_size__(8))); struct __mm_loadl_pi_struct { __mm_loadl_pi_v2f32 __u; } __attribute__((__packed__, __may_alias__)); __mm_loadl_pi_v2f32 __b = ((struct __mm_loadl_pi_struct*)__p)->__u; __m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1); return __builtin_shufflevector(__a, __bb, 4, 5, 2, 3); } /// \brief Constructs a 128-bit floating-point vector of [4 x float]. The lower /// 32 bits of the vector are initialized with the single-precision /// floating-point value loaded from a specified memory location. The upper /// 96 bits are set to zero. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVSS / MOVSS instruction. /// /// \param __p /// A pointer to a 32-bit memory location containing a single-precision /// floating-point value. /// \returns An initialized 128-bit floating-point vector of [4 x float]. The /// lower 32 bits contain the value loaded from the memory location. The /// upper 96 bits are set to zero. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_load_ss(const float *__p) { struct __mm_load_ss_struct { float __u; } __attribute__((__packed__, __may_alias__)); float __u = ((struct __mm_load_ss_struct*)__p)->__u; return (__m128){ __u, 0, 0, 0 }; } /// \brief Loads a 32-bit float value and duplicates it to all four vector /// elements of a 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVSS / MOVSS + shuffling /// instruction. /// /// \param __p /// A pointer to a float value to be loaded and duplicated. /// \returns A 128-bit vector of [4 x float] containing the loaded and /// duplicated values. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_load1_ps(const float *__p) { struct __mm_load1_ps_struct { float __u; } __attribute__((__packed__, __may_alias__)); float __u = ((struct __mm_load1_ps_struct*)__p)->__u; return (__m128){ __u, __u, __u, __u }; } #define _mm_load_ps1(p) _mm_load1_ps(p) /// \brief Loads a 128-bit floating-point vector of [4 x float] from an aligned /// memory location. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVAPS / MOVAPS instruction. /// /// \param __p /// A pointer to a 128-bit memory location. The address of the memory /// location has to be 128-bit aligned. /// \returns A 128-bit vector of [4 x float] containing the loaded valus. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_load_ps(const float *__p) { return *(__m128*)__p; } /// \brief Loads a 128-bit floating-point vector of [4 x float] from an /// unaligned memory location. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVUPS / MOVUPS instruction. /// /// \param __p /// A pointer to a 128-bit memory location. The address of the memory /// location does not have to be aligned. /// \returns A 128-bit vector of [4 x float] containing the loaded values. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_loadu_ps(const float *__p) { struct __loadu_ps { __m128 __v; } __attribute__((__packed__, __may_alias__)); return ((struct __loadu_ps*)__p)->__v; } /// \brief Loads four packed float values, in reverse order, from an aligned /// memory location to 32-bit elements in a 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVAPS / MOVAPS + shuffling /// instruction. /// /// \param __p /// A pointer to a 128-bit memory location. The address of the memory /// location has to be 128-bit aligned. /// \returns A 128-bit vector of [4 x float] containing the moved values, loaded /// in reverse order. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_loadr_ps(const float *__p) { __m128 __a = _mm_load_ps(__p); return __builtin_shufflevector((__v4sf)__a, (__v4sf)__a, 3, 2, 1, 0); } /// \brief Create a 128-bit vector of [4 x float] with undefined values. /// /// \headerfile /// /// This intrinsic has no corresponding instruction. /// /// \returns A 128-bit vector of [4 x float] containing undefined values. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_undefined_ps(void) { return (__m128)__builtin_ia32_undef128(); } /// \brief Constructs a 128-bit floating-point vector of [4 x float]. The lower /// 32 bits of the vector are initialized with the specified single-precision /// floating-point value. The upper 96 bits are set to zero. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVSS / MOVSS instruction. /// /// \param __w /// A single-precision floating-point value used to initialize the lower 32 /// bits of the result. /// \returns An initialized 128-bit floating-point vector of [4 x float]. The /// lower 32 bits contain the value provided in the source operand. The /// upper 96 bits are set to zero. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_set_ss(float __w) { return (__m128){ __w, 0, 0, 0 }; } /// \brief Constructs a 128-bit floating-point vector of [4 x float], with each /// of the four single-precision floating-point vector elements set to the /// specified single-precision floating-point value. /// /// \headerfile /// /// This intrinsic corresponds to the VPERMILPS / PERMILPS instruction. /// /// \param __w /// A single-precision floating-point value used to initialize each vector /// element of the result. /// \returns An initialized 128-bit floating-point vector of [4 x float]. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_set1_ps(float __w) { return (__m128){ __w, __w, __w, __w }; } /* Microsoft specific. */ /// \brief Constructs a 128-bit floating-point vector of [4 x float], with each /// of the four single-precision floating-point vector elements set to the /// specified single-precision floating-point value. /// /// \headerfile /// /// This intrinsic corresponds to the VPERMILPS / PERMILPS instruction. /// /// \param __w /// A single-precision floating-point value used to initialize each vector /// element of the result. /// \returns An initialized 128-bit floating-point vector of [4 x float]. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_set_ps1(float __w) { return _mm_set1_ps(__w); } /// \brief Constructs a 128-bit floating-point vector of [4 x float] /// initialized with the specified single-precision floating-point values. /// /// \headerfile /// /// This intrinsic is a utility function and does not correspond to a specific /// instruction. /// /// \param __z /// A single-precision floating-point value used to initialize bits [127:96] /// of the result. /// \param __y /// A single-precision floating-point value used to initialize bits [95:64] /// of the result. /// \param __x /// A single-precision floating-point value used to initialize bits [63:32] /// of the result. /// \param __w /// A single-precision floating-point value used to initialize bits [31:0] /// of the result. /// \returns An initialized 128-bit floating-point vector of [4 x float]. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_set_ps(float __z, float __y, float __x, float __w) { return (__m128){ __w, __x, __y, __z }; } /// \brief Constructs a 128-bit floating-point vector of [4 x float], /// initialized in reverse order with the specified 32-bit single-precision /// float-point values. /// /// \headerfile /// /// This intrinsic is a utility function and does not correspond to a specific /// instruction. /// /// \param __z /// A single-precision floating-point value used to initialize bits [31:0] /// of the result. /// \param __y /// A single-precision floating-point value used to initialize bits [63:32] /// of the result. /// \param __x /// A single-precision floating-point value used to initialize bits [95:64] /// of the result. /// \param __w /// A single-precision floating-point value used to initialize bits [127:96] /// of the result. /// \returns An initialized 128-bit floating-point vector of [4 x float]. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_setr_ps(float __z, float __y, float __x, float __w) { return (__m128){ __z, __y, __x, __w }; } /// \brief Constructs a 128-bit floating-point vector of [4 x float] initialized /// to zero. /// /// \headerfile /// /// This intrinsic corresponds to the VXORPS / XORPS instruction. /// /// \returns An initialized 128-bit floating-point vector of [4 x float] with /// all elements set to zero. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_setzero_ps(void) { return (__m128){ 0, 0, 0, 0 }; } /// \brief Stores the upper 64 bits of a 128-bit vector of [4 x float] to a /// memory location. /// /// \headerfile /// /// This intrinsic corresponds to the VPEXTRQ / MOVQ instruction. /// /// \param __p /// A pointer to a 64-bit memory location. /// \param __a /// A 128-bit vector of [4 x float] containing the values to be stored. static __inline__ void __DEFAULT_FN_ATTRS _mm_storeh_pi(__m64 *__p, __m128 __a) { __builtin_ia32_storehps((__v2si *)__p, (__v4sf)__a); } /// \brief Stores the lower 64 bits of a 128-bit vector of [4 x float] to a /// memory location. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVLPS / MOVLPS instruction. /// /// \param __p /// A pointer to a memory location that will receive the float values. /// \param __a /// A 128-bit vector of [4 x float] containing the values to be stored. static __inline__ void __DEFAULT_FN_ATTRS _mm_storel_pi(__m64 *__p, __m128 __a) { __builtin_ia32_storelps((__v2si *)__p, (__v4sf)__a); } /// \brief Stores the lower 32 bits of a 128-bit vector of [4 x float] to a /// memory location. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVSS / MOVSS instruction. /// /// \param __p /// A pointer to a 32-bit memory location. /// \param __a /// A 128-bit vector of [4 x float] containing the value to be stored. static __inline__ void __DEFAULT_FN_ATTRS _mm_store_ss(float *__p, __m128 __a) { struct __mm_store_ss_struct { float __u; } __attribute__((__packed__, __may_alias__)); ((struct __mm_store_ss_struct*)__p)->__u = __a[0]; } /// \brief Stores a 128-bit vector of [4 x float] to an unaligned memory /// location. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVUPS / MOVUPS instruction. /// /// \param __p /// A pointer to a 128-bit memory location. The address of the memory /// location does not have to be aligned. /// \param __a /// A 128-bit vector of [4 x float] containing the values to be stored. static __inline__ void __DEFAULT_FN_ATTRS _mm_storeu_ps(float *__p, __m128 __a) { struct __storeu_ps { __m128 __v; } __attribute__((__packed__, __may_alias__)); ((struct __storeu_ps*)__p)->__v = __a; } /// \brief Stores a 128-bit vector of [4 x float] into an aligned memory /// location. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVAPS / MOVAPS instruction. /// /// \param __p /// A pointer to a 128-bit memory location. The address of the memory /// location has to be 16-byte aligned. /// \param __a /// A 128-bit vector of [4 x float] containing the values to be stored. static __inline__ void __DEFAULT_FN_ATTRS _mm_store_ps(float *__p, __m128 __a) { *(__m128*)__p = __a; } /// \brief Stores the lower 32 bits of a 128-bit vector of [4 x float] into /// four contiguous elements in an aligned memory location. /// /// \headerfile /// /// This intrinsic corresponds to VMOVAPS / MOVAPS + shuffling /// instruction. /// /// \param __p /// A pointer to a 128-bit memory location. /// \param __a /// A 128-bit vector of [4 x float] whose lower 32 bits are stored to each /// of the four contiguous elements pointed by \a __p. static __inline__ void __DEFAULT_FN_ATTRS _mm_store1_ps(float *__p, __m128 __a) { __a = __builtin_shufflevector((__v4sf)__a, (__v4sf)__a, 0, 0, 0, 0); _mm_store_ps(__p, __a); } /// \brief Stores the lower 32 bits of a 128-bit vector of [4 x float] into /// four contiguous elements in an aligned memory location. /// /// \headerfile /// /// This intrinsic corresponds to VMOVAPS / MOVAPS + shuffling /// instruction. /// /// \param __p /// A pointer to a 128-bit memory location. /// \param __a /// A 128-bit vector of [4 x float] whose lower 32 bits are stored to each /// of the four contiguous elements pointed by \a __p. static __inline__ void __DEFAULT_FN_ATTRS _mm_store_ps1(float *__p, __m128 __a) { return _mm_store1_ps(__p, __a); } /// \brief Stores float values from a 128-bit vector of [4 x float] to an /// aligned memory location in reverse order. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVAPS / MOVAPS + shuffling /// instruction. /// /// \param __p /// A pointer to a 128-bit memory location. The address of the memory /// location has to be 128-bit aligned. /// \param __a /// A 128-bit vector of [4 x float] containing the values to be stored. static __inline__ void __DEFAULT_FN_ATTRS _mm_storer_ps(float *__p, __m128 __a) { __a = __builtin_shufflevector((__v4sf)__a, (__v4sf)__a, 3, 2, 1, 0); _mm_store_ps(__p, __a); } #define _MM_HINT_T0 3 #define _MM_HINT_T1 2 #define _MM_HINT_T2 1 #define _MM_HINT_NTA 0 #ifndef _MSC_VER /* FIXME: We have to #define this because "sel" must be a constant integer, and Sema doesn't do any form of constant propagation yet. */ /// \brief Loads one cache line of data from the specified address to a location /// closer to the processor. /// /// \headerfile /// /// \code /// void _mm_prefetch(const void * a, const int sel); /// \endcode /// /// This intrinsic corresponds to the PREFETCHNTA instruction. /// /// \param a /// A pointer to a memory location containing a cache line of data. /// \param sel /// A predefined integer constant specifying the type of prefetch /// operation: \n /// _MM_HINT_NTA: Move data using the non-temporal access (NTA) hint. The /// PREFETCHNTA instruction will be generated. \n /// _MM_HINT_T0: Move data using the T0 hint. The PREFETCHT0 instruction will /// be generated. \n /// _MM_HINT_T1: Move data using the T1 hint. The PREFETCHT1 instruction will /// be generated. \n /// _MM_HINT_T2: Move data using the T2 hint. The PREFETCHT2 instruction will /// be generated. #define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, (sel))) #endif /// \brief Stores a 64-bit integer in the specified aligned memory location. To /// minimize caching, the data is flagged as non-temporal (unlikely to be /// used again soon). /// /// \headerfile /// /// This intrinsic corresponds to the MOVNTQ instruction. /// /// \param __p /// A pointer to an aligned memory location used to store the register value. /// \param __a /// A 64-bit integer containing the value to be stored. static __inline__ void __DEFAULT_FN_ATTRS _mm_stream_pi(__m64 *__p, __m64 __a) { __builtin_ia32_movntq(__p, __a); } /// \brief Moves packed float values from a 128-bit vector of [4 x float] to a /// 128-bit aligned memory location. To minimize caching, the data is flagged /// as non-temporal (unlikely to be used again soon). /// /// \headerfile /// /// This intrinsic corresponds to the VMOVNTPS / MOVNTPS instruction. /// /// \param __p /// A pointer to a 128-bit aligned memory location that will receive the /// integer values. /// \param __a /// A 128-bit vector of [4 x float] containing the values to be moved. static __inline__ void __DEFAULT_FN_ATTRS _mm_stream_ps(float *__p, __m128 __a) { __builtin_nontemporal_store((__v4sf)__a, (__v4sf*)__p); } #if defined(__cplusplus) extern "C" { #endif /// \brief Forces strong memory ordering (serialization) between store /// instructions preceding this instruction and store instructions following /// this instruction, ensuring the system completes all previous stores /// before executing subsequent stores. /// /// \headerfile /// /// This intrinsic corresponds to the SFENCE instruction. /// void _mm_sfence(void); #if defined(__cplusplus) } // extern "C" #endif /// \brief Extracts 16-bit element from a 64-bit vector of [4 x i16] and /// returns it, as specified by the immediate integer operand. /// /// \headerfile /// /// \code -/// void _mm_extract_pi(__m64 a, int n); +/// int _mm_extract_pi16(__m64 a, int n); /// \endcode /// /// This intrinsic corresponds to the VPEXTRW / PEXTRW instruction. /// /// \param a /// A 64-bit vector of [4 x i16]. /// \param n /// An immediate integer operand that determines which bits are extracted: \n /// 0: Bits [15:0] are copied to the destination. \n /// 1: Bits [31:16] are copied to the destination. \n /// 2: Bits [47:32] are copied to the destination. \n /// 3: Bits [63:48] are copied to the destination. /// \returns A 16-bit integer containing the extracted 16 bits of packed data. #define _mm_extract_pi16(a, n) __extension__ ({ \ (int)__builtin_ia32_vec_ext_v4hi((__m64)a, (int)n); }) /// \brief Copies data from the 64-bit vector of [4 x i16] to the destination, /// and inserts the lower 16-bits of an integer operand at the 16-bit offset /// specified by the immediate operand \a n. /// /// \headerfile /// /// \code -/// void _mm_insert_pi(__m64 a, int d, int n); +/// __m64 _mm_insert_pi16(__m64 a, int d, int n); /// \endcode /// /// This intrinsic corresponds to the VPINSRW / PINSRW instruction. /// /// \param a /// A 64-bit vector of [4 x i16]. /// \param d /// An integer. The lower 16-bit value from this operand is written to the /// destination at the offset specified by operand \a n. /// \param n /// An immediate integer operant that determines which the bits to be used /// in the destination. \n /// 0: Bits [15:0] are copied to the destination. \n /// 1: Bits [31:16] are copied to the destination. \n /// 2: Bits [47:32] are copied to the destination. \n /// 3: Bits [63:48] are copied to the destination. \n /// The remaining bits in the destination are copied from the corresponding /// bits in operand \a a. /// \returns A 64-bit integer vector containing the copied packed data from the /// operands. #define _mm_insert_pi16(a, d, n) __extension__ ({ \ (__m64)__builtin_ia32_vec_set_v4hi((__m64)a, (int)d, (int)n); }) /// \brief Compares each of the corresponding packed 16-bit integer values of /// the 64-bit integer vectors, and writes the greater value to the /// corresponding bits in the destination. /// /// \headerfile /// /// This intrinsic corresponds to the PMAXSW instruction. /// /// \param __a /// A 64-bit integer vector containing one of the source operands. /// \param __b /// A 64-bit integer vector containing one of the source operands. /// \returns A 64-bit integer vector containing the comparison results. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_max_pi16(__m64 __a, __m64 __b) { return (__m64)__builtin_ia32_pmaxsw((__v4hi)__a, (__v4hi)__b); } /// \brief Compares each of the corresponding packed 8-bit unsigned integer /// values of the 64-bit integer vectors, and writes the greater value to the /// corresponding bits in the destination. /// /// \headerfile /// /// This intrinsic corresponds to the PMAXUB instruction. /// /// \param __a /// A 64-bit integer vector containing one of the source operands. /// \param __b /// A 64-bit integer vector containing one of the source operands. /// \returns A 64-bit integer vector containing the comparison results. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_max_pu8(__m64 __a, __m64 __b) { return (__m64)__builtin_ia32_pmaxub((__v8qi)__a, (__v8qi)__b); } /// \brief Compares each of the corresponding packed 16-bit integer values of /// the 64-bit integer vectors, and writes the lesser value to the /// corresponding bits in the destination. /// /// \headerfile /// /// This intrinsic corresponds to the PMINSW instruction. /// /// \param __a /// A 64-bit integer vector containing one of the source operands. /// \param __b /// A 64-bit integer vector containing one of the source operands. /// \returns A 64-bit integer vector containing the comparison results. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_min_pi16(__m64 __a, __m64 __b) { return (__m64)__builtin_ia32_pminsw((__v4hi)__a, (__v4hi)__b); } /// \brief Compares each of the corresponding packed 8-bit unsigned integer /// values of the 64-bit integer vectors, and writes the lesser value to the /// corresponding bits in the destination. /// /// \headerfile /// /// This intrinsic corresponds to the PMINUB instruction. /// /// \param __a /// A 64-bit integer vector containing one of the source operands. /// \param __b /// A 64-bit integer vector containing one of the source operands. /// \returns A 64-bit integer vector containing the comparison results. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_min_pu8(__m64 __a, __m64 __b) { return (__m64)__builtin_ia32_pminub((__v8qi)__a, (__v8qi)__b); } /// \brief Takes the most significant bit from each 8-bit element in a 64-bit /// integer vector to create a 16-bit mask value. Zero-extends the value to /// 32-bit integer and writes it to the destination. /// /// \headerfile /// /// This intrinsic corresponds to the PMOVMSKB instruction. /// /// \param __a /// A 64-bit integer vector containing the values with bits to be extracted. /// \returns The most significant bit from each 8-bit element in the operand, /// written to bits [15:0]. static __inline__ int __DEFAULT_FN_ATTRS _mm_movemask_pi8(__m64 __a) { return __builtin_ia32_pmovmskb((__v8qi)__a); } /// \brief Multiplies packed 16-bit unsigned integer values and writes the /// high-order 16 bits of each 32-bit product to the corresponding bits in /// the destination. /// /// \headerfile /// /// This intrinsic corresponds to the PMULHUW instruction. /// /// \param __a /// A 64-bit integer vector containing one of the source operands. /// \param __b /// A 64-bit integer vector containing one of the source operands. /// \returns A 64-bit integer vector containing the products of both operands. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_mulhi_pu16(__m64 __a, __m64 __b) { return (__m64)__builtin_ia32_pmulhuw((__v4hi)__a, (__v4hi)__b); } /// \brief Shuffles the 4 16-bit integers from a 64-bit integer vector to the /// destination, as specified by the immediate value operand. /// /// \headerfile /// /// \code /// __m64 _mm_shuffle_pi16(__m64 a, const int n); /// \endcode /// /// This intrinsic corresponds to the PSHUFW instruction. /// /// \param a /// A 64-bit integer vector containing the values to be shuffled. /// \param n /// An immediate value containing an 8-bit value specifying which elements to /// copy from \a a. The destinations within the 64-bit destination are /// assigned values as follows: \n /// Bits [1:0] are used to assign values to bits [15:0] in the /// destination. \n /// Bits [3:2] are used to assign values to bits [31:16] in the /// destination. \n /// Bits [5:4] are used to assign values to bits [47:32] in the /// destination. \n /// Bits [7:6] are used to assign values to bits [63:48] in the /// destination. \n /// Bit value assignments: \n /// 00: assigned from bits [15:0] of \a a. \n /// 01: assigned from bits [31:16] of \a a. \n /// 10: assigned from bits [47:32] of \a a. \n /// 11: assigned from bits [63:48] of \a a. /// \returns A 64-bit integer vector containing the shuffled values. #define _mm_shuffle_pi16(a, n) __extension__ ({ \ (__m64)__builtin_ia32_pshufw((__v4hi)(__m64)(a), (n)); }) /// \brief Conditionally copies the values from each 8-bit element in the first /// 64-bit integer vector operand to the specified memory location, as /// specified by the most significant bit in the corresponding element in the /// second 64-bit integer vector operand. /// /// To minimize caching, the data is flagged as non-temporal /// (unlikely to be used again soon). /// /// \headerfile /// /// This intrinsic corresponds to the MASKMOVQ instruction. /// /// \param __d /// A 64-bit integer vector containing the values with elements to be copied. /// \param __n /// A 64-bit integer vector operand. The most significant bit from each 8-bit /// element determines whether the corresponding element in operand \a __d /// is copied. If the most significant bit of a given element is 1, the /// corresponding element in operand \a __d is copied. /// \param __p /// A pointer to a 64-bit memory location that will receive the conditionally /// copied integer values. The address of the memory location does not have /// to be aligned. static __inline__ void __DEFAULT_FN_ATTRS _mm_maskmove_si64(__m64 __d, __m64 __n, char *__p) { __builtin_ia32_maskmovq((__v8qi)__d, (__v8qi)__n, __p); } /// \brief Computes the rounded averages of the packed unsigned 8-bit integer /// values and writes the averages to the corresponding bits in the /// destination. /// /// \headerfile /// /// This intrinsic corresponds to the PAVGB instruction. /// /// \param __a /// A 64-bit integer vector containing one of the source operands. /// \param __b /// A 64-bit integer vector containing one of the source operands. /// \returns A 64-bit integer vector containing the averages of both operands. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_avg_pu8(__m64 __a, __m64 __b) { return (__m64)__builtin_ia32_pavgb((__v8qi)__a, (__v8qi)__b); } /// \brief Computes the rounded averages of the packed unsigned 16-bit integer /// values and writes the averages to the corresponding bits in the /// destination. /// /// \headerfile /// /// This intrinsic corresponds to the PAVGW instruction. /// /// \param __a /// A 64-bit integer vector containing one of the source operands. /// \param __b /// A 64-bit integer vector containing one of the source operands. /// \returns A 64-bit integer vector containing the averages of both operands. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_avg_pu16(__m64 __a, __m64 __b) { return (__m64)__builtin_ia32_pavgw((__v4hi)__a, (__v4hi)__b); } /// \brief Subtracts the corresponding 8-bit unsigned integer values of the two /// 64-bit vector operands and computes the absolute value for each of the /// difference. Then sum of the 8 absolute differences is written to the /// bits [15:0] of the destination; the remaining bits [63:16] are cleared. /// /// \headerfile /// /// This intrinsic corresponds to the PSADBW instruction. /// /// \param __a /// A 64-bit integer vector containing one of the source operands. /// \param __b /// A 64-bit integer vector containing one of the source operands. /// \returns A 64-bit integer vector whose lower 16 bits contain the sums of the /// sets of absolute differences between both operands. The upper bits are /// cleared. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_sad_pu8(__m64 __a, __m64 __b) { return (__m64)__builtin_ia32_psadbw((__v8qi)__a, (__v8qi)__b); } #if defined(__cplusplus) extern "C" { #endif /// \brief Returns the contents of the MXCSR register as a 32-bit unsigned /// integer value. /// /// There are several groups of macros associated with this /// intrinsic, including: ///
    ///
  • /// For checking exception states: _MM_EXCEPT_INVALID, _MM_EXCEPT_DIV_ZERO, /// _MM_EXCEPT_DENORM, _MM_EXCEPT_OVERFLOW, _MM_EXCEPT_UNDERFLOW, /// _MM_EXCEPT_INEXACT. There is a convenience wrapper /// _MM_GET_EXCEPTION_STATE(). ///
  • ///
  • /// For checking exception masks: _MM_MASK_UNDERFLOW, _MM_MASK_OVERFLOW, /// _MM_MASK_INVALID, _MM_MASK_DENORM, _MM_MASK_DIV_ZERO, _MM_MASK_INEXACT. /// There is a convenience wrapper _MM_GET_EXCEPTION_MASK(). ///
  • ///
  • /// For checking rounding modes: _MM_ROUND_NEAREST, _MM_ROUND_DOWN, /// _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO. There is a convenience wrapper /// _MM_GET_ROUNDING_MODE(x) where x is one of these macros. ///
  • ///
  • /// For checking flush-to-zero mode: _MM_FLUSH_ZERO_ON, _MM_FLUSH_ZERO_OFF. /// There is a convenience wrapper _MM_GET_FLUSH_ZERO_MODE(). ///
  • ///
  • /// For checking denormals-are-zero mode: _MM_DENORMALS_ZERO_ON, /// _MM_DENORMALS_ZERO_OFF. There is a convenience wrapper /// _MM_GET_DENORMALS_ZERO_MODE(). ///
  • ///
/// /// For example, the expression below checks if an overflow exception has /// occurred: /// ( _mm_getcsr() & _MM_EXCEPT_OVERFLOW ) /// /// The following example gets the current rounding mode: /// _MM_GET_ROUNDING_MODE() /// /// \headerfile /// /// This intrinsic corresponds to the VSTMXCSR / STMXCSR instruction. /// /// \returns A 32-bit unsigned integer containing the contents of the MXCSR /// register. unsigned int _mm_getcsr(void); /// \brief Sets the MXCSR register with the 32-bit unsigned integer value. /// /// There are several groups of macros associated with this intrinsic, /// including: ///
    ///
  • /// For setting exception states: _MM_EXCEPT_INVALID, _MM_EXCEPT_DIV_ZERO, /// _MM_EXCEPT_DENORM, _MM_EXCEPT_OVERFLOW, _MM_EXCEPT_UNDERFLOW, /// _MM_EXCEPT_INEXACT. There is a convenience wrapper /// _MM_SET_EXCEPTION_STATE(x) where x is one of these macros. ///
  • ///
  • /// For setting exception masks: _MM_MASK_UNDERFLOW, _MM_MASK_OVERFLOW, /// _MM_MASK_INVALID, _MM_MASK_DENORM, _MM_MASK_DIV_ZERO, _MM_MASK_INEXACT. /// There is a convenience wrapper _MM_SET_EXCEPTION_MASK(x) where x is one /// of these macros. ///
  • ///
  • /// For setting rounding modes: _MM_ROUND_NEAREST, _MM_ROUND_DOWN, /// _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO. There is a convenience wrapper /// _MM_SET_ROUNDING_MODE(x) where x is one of these macros. ///
  • ///
  • /// For setting flush-to-zero mode: _MM_FLUSH_ZERO_ON, _MM_FLUSH_ZERO_OFF. /// There is a convenience wrapper _MM_SET_FLUSH_ZERO_MODE(x) where x is /// one of these macros. ///
  • ///
  • /// For setting denormals-are-zero mode: _MM_DENORMALS_ZERO_ON, /// _MM_DENORMALS_ZERO_OFF. There is a convenience wrapper /// _MM_SET_DENORMALS_ZERO_MODE(x) where x is one of these macros. ///
  • ///
/// /// For example, the following expression causes subsequent floating-point /// operations to round up: /// _mm_setcsr(_mm_getcsr() | _MM_ROUND_UP) /// /// The following example sets the DAZ and FTZ flags: /// void setFlags() { /// _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON) /// _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON) /// } /// /// \headerfile /// /// This intrinsic corresponds to the VLDMXCSR / LDMXCSR instruction. /// /// \param __i /// A 32-bit unsigned integer value to be written to the MXCSR register. void _mm_setcsr(unsigned int __i); #if defined(__cplusplus) } // extern "C" #endif /// \brief Selects 4 float values from the 128-bit operands of [4 x float], as /// specified by the immediate value operand. /// /// \headerfile /// /// \code /// __m128 _mm_shuffle_ps(__m128 a, __m128 b, const int mask); /// \endcode /// /// This intrinsic corresponds to the VSHUFPS / SHUFPS instruction. /// /// \param a /// A 128-bit vector of [4 x float]. /// \param b /// A 128-bit vector of [4 x float]. /// \param mask /// An immediate value containing an 8-bit value specifying which elements to /// copy from \a a and \a b. \n /// Bits [3:0] specify the values copied from operand \a a. \n /// Bits [7:4] specify the values copied from operand \a b. \n /// The destinations within the 128-bit destination are assigned values as /// follows: \n /// Bits [1:0] are used to assign values to bits [31:0] in the /// destination. \n /// Bits [3:2] are used to assign values to bits [63:32] in the /// destination. \n /// Bits [5:4] are used to assign values to bits [95:64] in the /// destination. \n /// Bits [7:6] are used to assign values to bits [127:96] in the /// destination. \n /// Bit value assignments: \n /// 00: Bits [31:0] copied from the specified operand. \n /// 01: Bits [63:32] copied from the specified operand. \n /// 10: Bits [95:64] copied from the specified operand. \n /// 11: Bits [127:96] copied from the specified operand. /// \returns A 128-bit vector of [4 x float] containing the shuffled values. #define _mm_shuffle_ps(a, b, mask) __extension__ ({ \ (__m128)__builtin_shufflevector((__v4sf)(__m128)(a), (__v4sf)(__m128)(b), \ 0 + (((mask) >> 0) & 0x3), \ 0 + (((mask) >> 2) & 0x3), \ 4 + (((mask) >> 4) & 0x3), \ 4 + (((mask) >> 6) & 0x3)); }) /// \brief Unpacks the high-order (index 2,3) values from two 128-bit vectors of /// [4 x float] and interleaves them into a 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VUNPCKHPS / UNPCKHPS instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. \n /// Bits [95:64] are written to bits [31:0] of the destination. \n /// Bits [127:96] are written to bits [95:64] of the destination. /// \param __b /// A 128-bit vector of [4 x float]. /// Bits [95:64] are written to bits [63:32] of the destination. \n /// Bits [127:96] are written to bits [127:96] of the destination. /// \returns A 128-bit vector of [4 x float] containing the interleaved values. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_unpackhi_ps(__m128 __a, __m128 __b) { return __builtin_shufflevector((__v4sf)__a, (__v4sf)__b, 2, 6, 3, 7); } /// \brief Unpacks the low-order (index 0,1) values from two 128-bit vectors of /// [4 x float] and interleaves them into a 128-bit vector of [4 x float]. /// /// \headerfile /// /// This intrinsic corresponds to the VUNPCKLPS / UNPCKLPS instruction. /// /// \param __a /// A 128-bit vector of [4 x float]. \n /// Bits [31:0] are written to bits [31:0] of the destination. \n /// Bits [63:32] are written to bits [95:64] of the destination. /// \param __b /// A 128-bit vector of [4 x float]. \n /// Bits [31:0] are written to bits [63:32] of the destination. \n /// Bits [63:32] are written to bits [127:96] of the destination. /// \returns A 128-bit vector of [4 x float] containing the interleaved values. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_unpacklo_ps(__m128 __a, __m128 __b) { return __builtin_shufflevector((__v4sf)__a, (__v4sf)__b, 0, 4, 1, 5); } /// \brief Constructs a 128-bit floating-point vector of [4 x float]. The lower /// 32 bits are set to the lower 32 bits of the second parameter. The upper /// 96 bits are set to the upper 96 bits of the first parameter. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVSS / MOVSS instruction. /// /// \param __a /// A 128-bit floating-point vector of [4 x float]. The upper 96 bits are /// written to the upper 96 bits of the result. /// \param __b /// A 128-bit floating-point vector of [4 x float]. The lower 32 bits are /// written to the lower 32 bits of the result. /// \returns A 128-bit floating-point vector of [4 x float]. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_move_ss(__m128 __a, __m128 __b) { return __builtin_shufflevector((__v4sf)__a, (__v4sf)__b, 4, 1, 2, 3); } /// \brief Constructs a 128-bit floating-point vector of [4 x float]. The lower /// 64 bits are set to the upper 64 bits of the second parameter. The upper /// 64 bits are set to the upper 64 bits of the first parameter. /// /// \headerfile /// /// This intrinsic corresponds to the VUNPCKHPD / UNPCKHPD instruction. /// /// \param __a /// A 128-bit floating-point vector of [4 x float]. The upper 64 bits are /// written to the upper 64 bits of the result. /// \param __b /// A 128-bit floating-point vector of [4 x float]. The upper 64 bits are /// written to the lower 64 bits of the result. /// \returns A 128-bit floating-point vector of [4 x float]. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_movehl_ps(__m128 __a, __m128 __b) { return __builtin_shufflevector((__v4sf)__a, (__v4sf)__b, 6, 7, 2, 3); } /// \brief Constructs a 128-bit floating-point vector of [4 x float]. The lower /// 64 bits are set to the lower 64 bits of the first parameter. The upper /// 64 bits are set to the lower 64 bits of the second parameter. /// /// \headerfile /// /// This intrinsic corresponds to the VUNPCKLPD / UNPCKLPD instruction. /// /// \param __a /// A 128-bit floating-point vector of [4 x float]. The lower 64 bits are /// written to the lower 64 bits of the result. /// \param __b /// A 128-bit floating-point vector of [4 x float]. The lower 64 bits are /// written to the upper 64 bits of the result. /// \returns A 128-bit floating-point vector of [4 x float]. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_movelh_ps(__m128 __a, __m128 __b) { return __builtin_shufflevector((__v4sf)__a, (__v4sf)__b, 0, 1, 4, 5); } /// \brief Converts a 64-bit vector of [4 x i16] into a 128-bit vector of [4 x /// float]. /// /// \headerfile /// -/// This intrinsic corresponds to the CVTPI2PS + \c COMPOSITE -/// instruction. +/// This intrinsic corresponds to the CVTPI2PS + COMPOSITE instruction. /// /// \param __a /// A 64-bit vector of [4 x i16]. The elements of the destination are copied /// from the corresponding elements in this operand. /// \returns A 128-bit vector of [4 x float] containing the copied and converted /// values from the operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtpi16_ps(__m64 __a) { __m64 __b, __c; __m128 __r; __b = _mm_setzero_si64(); __b = _mm_cmpgt_pi16(__b, __a); __c = _mm_unpackhi_pi16(__a, __b); __r = _mm_setzero_ps(); __r = _mm_cvtpi32_ps(__r, __c); __r = _mm_movelh_ps(__r, __r); __c = _mm_unpacklo_pi16(__a, __b); __r = _mm_cvtpi32_ps(__r, __c); return __r; } /// \brief Converts a 64-bit vector of 16-bit unsigned integer values into a /// 128-bit vector of [4 x float]. /// /// \headerfile /// -/// This intrinsic corresponds to the CVTPI2PS + \c COMPOSITE -/// instruction. +/// This intrinsic corresponds to the CVTPI2PS + COMPOSITE instruction. /// /// \param __a /// A 64-bit vector of 16-bit unsigned integer values. The elements of the /// destination are copied from the corresponding elements in this operand. /// \returns A 128-bit vector of [4 x float] containing the copied and converted /// values from the operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtpu16_ps(__m64 __a) { __m64 __b, __c; __m128 __r; __b = _mm_setzero_si64(); __c = _mm_unpackhi_pi16(__a, __b); __r = _mm_setzero_ps(); __r = _mm_cvtpi32_ps(__r, __c); __r = _mm_movelh_ps(__r, __r); __c = _mm_unpacklo_pi16(__a, __b); __r = _mm_cvtpi32_ps(__r, __c); return __r; } /// \brief Converts the lower four 8-bit values from a 64-bit vector of [8 x i8] /// into a 128-bit vector of [4 x float]. /// /// \headerfile /// -/// This intrinsic corresponds to the CVTPI2PS + \c COMPOSITE -/// instruction. +/// This intrinsic corresponds to the CVTPI2PS + COMPOSITE instruction. /// /// \param __a /// A 64-bit vector of [8 x i8]. The elements of the destination are copied /// from the corresponding lower 4 elements in this operand. /// \returns A 128-bit vector of [4 x float] containing the copied and converted /// values from the operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtpi8_ps(__m64 __a) { __m64 __b; __b = _mm_setzero_si64(); __b = _mm_cmpgt_pi8(__b, __a); __b = _mm_unpacklo_pi8(__a, __b); return _mm_cvtpi16_ps(__b); } /// \brief Converts the lower four unsigned 8-bit integer values from a 64-bit /// vector of [8 x u8] into a 128-bit vector of [4 x float]. /// /// \headerfile /// -/// This intrinsic corresponds to the CVTPI2PS + \c COMPOSITE -/// instruction. +/// This intrinsic corresponds to the CVTPI2PS + COMPOSITE instruction. /// /// \param __a /// A 64-bit vector of unsigned 8-bit integer values. The elements of the /// destination are copied from the corresponding lower 4 elements in this /// operand. /// \returns A 128-bit vector of [4 x float] containing the copied and converted /// values from the source operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtpu8_ps(__m64 __a) { __m64 __b; __b = _mm_setzero_si64(); __b = _mm_unpacklo_pi8(__a, __b); return _mm_cvtpi16_ps(__b); } /// \brief Converts the two 32-bit signed integer values from each 64-bit vector /// operand of [2 x i32] into a 128-bit vector of [4 x float]. /// /// \headerfile /// -/// This intrinsic corresponds to the CVTPI2PS + \c COMPOSITE -/// instruction. +/// This intrinsic corresponds to the CVTPI2PS + COMPOSITE instruction. /// /// \param __a /// A 64-bit vector of [2 x i32]. The lower elements of the destination are /// copied from the elements in this operand. /// \param __b /// A 64-bit vector of [2 x i32]. The upper elements of the destination are /// copied from the elements in this operand. /// \returns A 128-bit vector of [4 x float] whose lower 64 bits contain the /// copied and converted values from the first operand. The upper 64 bits /// contain the copied and converted values from the second operand. static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtpi32x2_ps(__m64 __a, __m64 __b) { __m128 __c; __c = _mm_setzero_ps(); __c = _mm_cvtpi32_ps(__c, __b); __c = _mm_movelh_ps(__c, __c); return _mm_cvtpi32_ps(__c, __a); } /// \brief Converts each single-precision floating-point element of a 128-bit /// floating-point vector of [4 x float] into a 16-bit signed integer, and /// packs the results into a 64-bit integer vector of [4 x i16]. /// /// If the floating-point element is NaN or infinity, or if the /// floating-point element is greater than 0x7FFFFFFF or less than -0x8000, /// it is converted to 0x8000. Otherwise if the floating-point element is /// greater than 0x7FFF, it is converted to 0x7FFF. /// /// \headerfile /// -/// This intrinsic corresponds to the CVTPS2PI + \c COMPOSITE -/// instruction. +/// This intrinsic corresponds to the CVTPS2PI + COMPOSITE instruction. /// /// \param __a /// A 128-bit floating-point vector of [4 x float]. /// \returns A 64-bit integer vector of [4 x i16] containing the converted /// values. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvtps_pi16(__m128 __a) { __m64 __b, __c; __b = _mm_cvtps_pi32(__a); __a = _mm_movehl_ps(__a, __a); __c = _mm_cvtps_pi32(__a); return _mm_packs_pi32(__b, __c); } /// \brief Converts each single-precision floating-point element of a 128-bit /// floating-point vector of [4 x float] into an 8-bit signed integer, and /// packs the results into the lower 32 bits of a 64-bit integer vector of /// [8 x i8]. The upper 32 bits of the vector are set to 0. /// /// If the floating-point element is NaN or infinity, or if the /// floating-point element is greater than 0x7FFFFFFF or less than -0x80, it /// is converted to 0x80. Otherwise if the floating-point element is greater /// than 0x7F, it is converted to 0x7F. /// /// \headerfile /// -/// This intrinsic corresponds to the CVTPS2PI + \c COMPOSITE -/// instruction. +/// This intrinsic corresponds to the CVTPS2PI + COMPOSITE instruction. /// /// \param __a /// 128-bit floating-point vector of [4 x float]. /// \returns A 64-bit integer vector of [8 x i8]. The lower 32 bits contain the /// converted values and the uppper 32 bits are set to zero. static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvtps_pi8(__m128 __a) { __m64 __b, __c; __b = _mm_cvtps_pi16(__a); __c = _mm_setzero_si64(); return _mm_packs_pi16(__b, __c); } /// \brief Extracts the sign bits from each single-precision floating-point /// element of a 128-bit floating-point vector of [4 x float] and returns the /// sign bits in bits [0:3] of the result. Bits [31:4] of the result are set /// to zero. /// /// \headerfile /// /// This intrinsic corresponds to the VMOVMSKPS / MOVMSKPS instruction. /// /// \param __a /// A 128-bit floating-point vector of [4 x float]. /// \returns A 32-bit integer value. Bits [3:0] contain the sign bits from each /// single-precision floating-point element of the parameter. Bits [31:4] are /// set to zero. static __inline__ int __DEFAULT_FN_ATTRS _mm_movemask_ps(__m128 __a) { return __builtin_ia32_movmskps((__v4sf)__a); } #define _MM_ALIGN16 __attribute__((aligned(16))) #define _MM_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) #define _MM_EXCEPT_INVALID (0x0001) #define _MM_EXCEPT_DENORM (0x0002) #define _MM_EXCEPT_DIV_ZERO (0x0004) #define _MM_EXCEPT_OVERFLOW (0x0008) #define _MM_EXCEPT_UNDERFLOW (0x0010) #define _MM_EXCEPT_INEXACT (0x0020) #define _MM_EXCEPT_MASK (0x003f) #define _MM_MASK_INVALID (0x0080) #define _MM_MASK_DENORM (0x0100) #define _MM_MASK_DIV_ZERO (0x0200) #define _MM_MASK_OVERFLOW (0x0400) #define _MM_MASK_UNDERFLOW (0x0800) #define _MM_MASK_INEXACT (0x1000) #define _MM_MASK_MASK (0x1f80) #define _MM_ROUND_NEAREST (0x0000) #define _MM_ROUND_DOWN (0x2000) #define _MM_ROUND_UP (0x4000) #define _MM_ROUND_TOWARD_ZERO (0x6000) #define _MM_ROUND_MASK (0x6000) #define _MM_FLUSH_ZERO_MASK (0x8000) #define _MM_FLUSH_ZERO_ON (0x8000) #define _MM_FLUSH_ZERO_OFF (0x0000) #define _MM_GET_EXCEPTION_MASK() (_mm_getcsr() & _MM_MASK_MASK) #define _MM_GET_EXCEPTION_STATE() (_mm_getcsr() & _MM_EXCEPT_MASK) #define _MM_GET_FLUSH_ZERO_MODE() (_mm_getcsr() & _MM_FLUSH_ZERO_MASK) #define _MM_GET_ROUNDING_MODE() (_mm_getcsr() & _MM_ROUND_MASK) #define _MM_SET_EXCEPTION_MASK(x) (_mm_setcsr((_mm_getcsr() & ~_MM_MASK_MASK) | (x))) #define _MM_SET_EXCEPTION_STATE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_EXCEPT_MASK) | (x))) #define _MM_SET_FLUSH_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_FLUSH_ZERO_MASK) | (x))) #define _MM_SET_ROUNDING_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_ROUND_MASK) | (x))) #define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \ do { \ __m128 tmp3, tmp2, tmp1, tmp0; \ tmp0 = _mm_unpacklo_ps((row0), (row1)); \ tmp2 = _mm_unpacklo_ps((row2), (row3)); \ tmp1 = _mm_unpackhi_ps((row0), (row1)); \ tmp3 = _mm_unpackhi_ps((row2), (row3)); \ (row0) = _mm_movelh_ps(tmp0, tmp2); \ (row1) = _mm_movehl_ps(tmp2, tmp0); \ (row2) = _mm_movelh_ps(tmp1, tmp3); \ (row3) = _mm_movehl_ps(tmp3, tmp1); \ } while (0) /* Aliases for compatibility. */ #define _m_pextrw _mm_extract_pi16 #define _m_pinsrw _mm_insert_pi16 #define _m_pmaxsw _mm_max_pi16 #define _m_pmaxub _mm_max_pu8 #define _m_pminsw _mm_min_pi16 #define _m_pminub _mm_min_pu8 #define _m_pmovmskb _mm_movemask_pi8 #define _m_pmulhuw _mm_mulhi_pu16 #define _m_pshufw _mm_shuffle_pi16 #define _m_maskmovq _mm_maskmove_si64 #define _m_pavgb _mm_avg_pu8 #define _m_pavgw _mm_avg_pu16 #define _m_psadbw _mm_sad_pu8 #define _m_ _mm_ #define _m_ _mm_ #undef __DEFAULT_FN_ATTRS /* Ugly hack for backwards-compatibility (compatible with gcc) */ #if defined(__SSE2__) && !__building_module(_Builtin_intrinsics) #include #endif #endif /* __XMMINTRIN_H */ Index: vendor/clang/dist/lib/Lex/Lexer.cpp =================================================================== --- vendor/clang/dist/lib/Lex/Lexer.cpp (revision 318415) +++ vendor/clang/dist/lib/Lex/Lexer.cpp (revision 318416) @@ -1,3752 +1,3756 @@ //===--- Lexer.cpp - C Language Family Lexer ------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Lexer and Token interfaces. // //===----------------------------------------------------------------------===// #include "clang/Lex/Lexer.h" #include "UnicodeCharSets.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/UnicodeCharRanges.h" #include #include #include #include #include #include #include #include using namespace clang; //===----------------------------------------------------------------------===// // Token Class Implementation //===----------------------------------------------------------------------===// /// isObjCAtKeyword - Return true if we have an ObjC keyword identifier. bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const { + if (isAnnotation()) + return false; if (IdentifierInfo *II = getIdentifierInfo()) return II->getObjCKeywordID() == objcKey; return false; } /// getObjCKeywordID - Return the ObjC keyword kind. tok::ObjCKeywordKind Token::getObjCKeywordID() const { + if (isAnnotation()) + return tok::objc_not_keyword; IdentifierInfo *specId = getIdentifierInfo(); return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword; } //===----------------------------------------------------------------------===// // Lexer Class Implementation //===----------------------------------------------------------------------===// void Lexer::anchor() { } void Lexer::InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd) { BufferStart = BufStart; BufferPtr = BufPtr; BufferEnd = BufEnd; assert(BufEnd[0] == 0 && "We assume that the input buffer has a null character at the end" " to simplify lexing!"); // Check whether we have a BOM in the beginning of the buffer. If yes - act // accordingly. Right now we support only UTF-8 with and without BOM, so, just // skip the UTF-8 BOM if it's present. if (BufferStart == BufferPtr) { // Determine the size of the BOM. StringRef Buf(BufferStart, BufferEnd - BufferStart); size_t BOMLength = llvm::StringSwitch(Buf) .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM .Default(0); // Skip the BOM. BufferPtr += BOMLength; } Is_PragmaLexer = false; CurrentConflictMarkerState = CMK_None; // Start of the file is a start of line. IsAtStartOfLine = true; IsAtPhysicalStartOfLine = true; HasLeadingSpace = false; HasLeadingEmptyMacro = false; // We are not after parsing a #. ParsingPreprocessorDirective = false; // We are not after parsing #include. ParsingFilename = false; // We are not in raw mode. Raw mode disables diagnostics and interpretation // of tokens (e.g. identifiers, thus disabling macro expansion). It is used // to quickly lex the tokens of the buffer, e.g. when handling a "#if 0" block // or otherwise skipping over tokens. LexingRawMode = false; // Default to not keeping comments. ExtendedTokenMode = 0; } /// Lexer constructor - Create a new lexer object for the specified buffer /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP) : PreprocessorLexer(&PP, FID), FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)), LangOpts(PP.getLangOpts()) { InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(), InputFile->getBufferEnd()); resetExtendedTokenMode(); } void Lexer::resetExtendedTokenMode() { assert(PP && "Cannot reset token mode without a preprocessor"); if (LangOpts.TraditionalCPP) SetKeepWhitespaceMode(true); else SetCommentRetentionState(PP->getCommentRetentionState()); } /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts, const char *BufStart, const char *BufPtr, const char *BufEnd) : FileLoc(fileloc), LangOpts(langOpts) { InitLexer(BufStart, BufPtr, BufEnd); // We *are* in raw mode. LexingRawMode = true; } /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile, const SourceManager &SM, const LangOptions &langOpts) : Lexer(SM.getLocForStartOfFile(FID), langOpts, FromFile->getBufferStart(), FromFile->getBufferStart(), FromFile->getBufferEnd()) {} /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for /// _Pragma expansion. This has a variety of magic semantics that this method /// sets up. It returns a new'd Lexer that must be delete'd when done. /// /// On entrance to this routine, TokStartLoc is a macro location which has a /// spelling loc that indicates the bytes to be lexed for the token and an /// expansion location that indicates where all lexed tokens should be /// "expanded from". /// /// TODO: It would really be nice to make _Pragma just be a wrapper around a /// normal lexer that remaps tokens as they fly by. This would require making /// Preprocessor::Lex virtual. Given that, we could just dump in a magic lexer /// interface that could handle this stuff. This would pull GetMappedTokenLoc /// out of the critical path of the lexer! /// Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc, SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd, unsigned TokLen, Preprocessor &PP) { SourceManager &SM = PP.getSourceManager(); // Create the lexer as if we were going to lex the file normally. FileID SpellingFID = SM.getFileID(SpellingLoc); const llvm::MemoryBuffer *InputFile = SM.getBuffer(SpellingFID); Lexer *L = new Lexer(SpellingFID, InputFile, PP); // Now that the lexer is created, change the start/end locations so that we // just lex the subsection of the file that we want. This is lexing from a // scratch buffer. const char *StrData = SM.getCharacterData(SpellingLoc); L->BufferPtr = StrData; L->BufferEnd = StrData+TokLen; assert(L->BufferEnd[0] == 0 && "Buffer is not nul terminated!"); // Set the SourceLocation with the remapping information. This ensures that // GetMappedTokenLoc will remap the tokens as they are lexed. L->FileLoc = SM.createExpansionLoc(SM.getLocForStartOfFile(SpellingFID), ExpansionLocStart, ExpansionLocEnd, TokLen); // Ensure that the lexer thinks it is inside a directive, so that end \n will // return an EOD token. L->ParsingPreprocessorDirective = true; // This lexer really is for _Pragma. L->Is_PragmaLexer = true; return L; } /// Stringify - Convert the specified string into a C string, with surrounding /// ""'s, and with escaped \ and " characters. std::string Lexer::Stringify(StringRef Str, bool Charify) { std::string Result = Str; char Quote = Charify ? '\'' : '"'; for (unsigned i = 0, e = Result.size(); i != e; ++i) { if (Result[i] == '\\' || Result[i] == Quote) { Result.insert(Result.begin()+i, '\\'); ++i; ++e; } } return Result; } /// Stringify - Convert the specified string into a C string by escaping '\' /// and " characters. This does not add surrounding ""'s to the string. void Lexer::Stringify(SmallVectorImpl &Str) { for (unsigned i = 0, e = Str.size(); i != e; ++i) { if (Str[i] == '\\' || Str[i] == '"') { Str.insert(Str.begin()+i, '\\'); ++i; ++e; } } } //===----------------------------------------------------------------------===// // Token Spelling //===----------------------------------------------------------------------===// /// \brief Slow case of getSpelling. Extract the characters comprising the /// spelling of this token from the provided input buffer. static size_t getSpellingSlow(const Token &Tok, const char *BufPtr, const LangOptions &LangOpts, char *Spelling) { assert(Tok.needsCleaning() && "getSpellingSlow called on simple token"); size_t Length = 0; const char *BufEnd = BufPtr + Tok.getLength(); if (tok::isStringLiteral(Tok.getKind())) { // Munch the encoding-prefix and opening double-quote. while (BufPtr < BufEnd) { unsigned Size; Spelling[Length++] = Lexer::getCharAndSizeNoWarn(BufPtr, Size, LangOpts); BufPtr += Size; if (Spelling[Length - 1] == '"') break; } // Raw string literals need special handling; trigraph expansion and line // splicing do not occur within their d-char-sequence nor within their // r-char-sequence. if (Length >= 2 && Spelling[Length - 2] == 'R' && Spelling[Length - 1] == '"') { // Search backwards from the end of the token to find the matching closing // quote. const char *RawEnd = BufEnd; do --RawEnd; while (*RawEnd != '"'); size_t RawLength = RawEnd - BufPtr + 1; // Everything between the quotes is included verbatim in the spelling. memcpy(Spelling + Length, BufPtr, RawLength); Length += RawLength; BufPtr += RawLength; // The rest of the token is lexed normally. } } while (BufPtr < BufEnd) { unsigned Size; Spelling[Length++] = Lexer::getCharAndSizeNoWarn(BufPtr, Size, LangOpts); BufPtr += Size; } assert(Length < Tok.getLength() && "NeedsCleaning flag set on token that didn't need cleaning!"); return Length; } /// getSpelling() - Return the 'spelling' of this token. The spelling of a /// token are the characters used to represent the token in the source file /// after trigraph expansion and escaped-newline folding. In particular, this /// wants to get the true, uncanonicalized, spelling of things like digraphs /// UCNs, etc. StringRef Lexer::getSpelling(SourceLocation loc, SmallVectorImpl &buffer, const SourceManager &SM, const LangOptions &options, bool *invalid) { // Break down the source location. std::pair locInfo = SM.getDecomposedLoc(loc); // Try to the load the file buffer. bool invalidTemp = false; StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) { if (invalid) *invalid = true; return StringRef(); } const char *tokenBegin = file.data() + locInfo.second; // Lex from the start of the given location. Lexer lexer(SM.getLocForStartOfFile(locInfo.first), options, file.begin(), tokenBegin, file.end()); Token token; lexer.LexFromRawLexer(token); unsigned length = token.getLength(); // Common case: no need for cleaning. if (!token.needsCleaning()) return StringRef(tokenBegin, length); // Hard case, we need to relex the characters into the string. buffer.resize(length); buffer.resize(getSpellingSlow(token, tokenBegin, options, buffer.data())); return StringRef(buffer.data(), buffer.size()); } /// getSpelling() - Return the 'spelling' of this token. The spelling of a /// token are the characters used to represent the token in the source file /// after trigraph expansion and escaped-newline folding. In particular, this /// wants to get the true, uncanonicalized, spelling of things like digraphs /// UCNs, etc. std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid) { assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); bool CharDataInvalid = false; const char *TokStart = SourceMgr.getCharacterData(Tok.getLocation(), &CharDataInvalid); if (Invalid) *Invalid = CharDataInvalid; if (CharDataInvalid) return std::string(); // If this token contains nothing interesting, return it directly. if (!Tok.needsCleaning()) return std::string(TokStart, TokStart + Tok.getLength()); std::string Result; Result.resize(Tok.getLength()); Result.resize(getSpellingSlow(Tok, TokStart, LangOpts, &*Result.begin())); return Result; } /// getSpelling - This method is used to get the spelling of a token into a /// preallocated buffer, instead of as an std::string. The caller is required /// to allocate enough space for the token, which is guaranteed to be at least /// Tok.getLength() bytes long. The actual length of the token is returned. /// /// Note that this method may do two possible things: it may either fill in /// the buffer specified with characters, or it may *change the input pointer* /// to point to a constant buffer with the data already in it (avoiding a /// copy). The caller is not allowed to modify the returned buffer pointer /// if an internal buffer is returned. unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid) { assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); const char *TokStart = nullptr; // NOTE: this has to be checked *before* testing for an IdentifierInfo. if (Tok.is(tok::raw_identifier)) TokStart = Tok.getRawIdentifier().data(); else if (!Tok.hasUCN()) { if (const IdentifierInfo *II = Tok.getIdentifierInfo()) { // Just return the string from the identifier table, which is very quick. Buffer = II->getNameStart(); return II->getLength(); } } // NOTE: this can be checked even after testing for an IdentifierInfo. if (Tok.isLiteral()) TokStart = Tok.getLiteralData(); if (!TokStart) { // Compute the start of the token in the input lexer buffer. bool CharDataInvalid = false; TokStart = SourceMgr.getCharacterData(Tok.getLocation(), &CharDataInvalid); if (Invalid) *Invalid = CharDataInvalid; if (CharDataInvalid) { Buffer = ""; return 0; } } // If this token contains nothing interesting, return it directly. if (!Tok.needsCleaning()) { Buffer = TokStart; return Tok.getLength(); } // Otherwise, hard case, relex the characters into the string. return getSpellingSlow(Tok, TokStart, LangOpts, const_cast(Buffer)); } /// MeasureTokenLength - Relex the token at the specified location and return /// its length in bytes in the input file. If the token needs cleaning (e.g. /// includes a trigraph or an escaped newline) then this count includes bytes /// that are part of that. unsigned Lexer::MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts) { Token TheTok; if (getRawToken(Loc, TheTok, SM, LangOpts)) return 0; return TheTok.getLength(); } /// \brief Relex the token at the specified location. /// \returns true if there was a failure, false on success. bool Lexer::getRawToken(SourceLocation Loc, Token &Result, const SourceManager &SM, const LangOptions &LangOpts, bool IgnoreWhiteSpace) { // TODO: this could be special cased for common tokens like identifiers, ')', // etc to make this faster, if it mattered. Just look at StrData[0] to handle // all obviously single-char tokens. This could use // Lexer::isObviouslySimpleCharacter for example to handle identifiers or // something. // If this comes from a macro expansion, we really do want the macro name, not // the token this macro expanded to. Loc = SM.getExpansionLoc(Loc); std::pair LocInfo = SM.getDecomposedLoc(Loc); bool Invalid = false; StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) return true; const char *StrData = Buffer.data()+LocInfo.second; if (!IgnoreWhiteSpace && isWhitespace(StrData[0])) return true; // Create a lexer starting at the beginning of this token. Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts, Buffer.begin(), StrData, Buffer.end()); TheLexer.SetCommentRetentionState(true); TheLexer.LexFromRawLexer(Result); return false; } /// Returns the pointer that points to the beginning of line that contains /// the given offset, or null if the offset if invalid. static const char *findBeginningOfLine(StringRef Buffer, unsigned Offset) { const char *BufStart = Buffer.data(); if (Offset >= Buffer.size()) return nullptr; const char *StrData = BufStart + Offset; if (StrData[0] == '\n' || StrData[0] == '\r') return StrData; const char *LexStart = StrData; while (LexStart != BufStart) { if (LexStart[0] == '\n' || LexStart[0] == '\r') { ++LexStart; break; } --LexStart; } return LexStart; } static SourceLocation getBeginningOfFileToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts) { assert(Loc.isFileID()); std::pair LocInfo = SM.getDecomposedLoc(Loc); if (LocInfo.first.isInvalid()) return Loc; bool Invalid = false; StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) return Loc; // Back up from the current location until we hit the beginning of a line // (or the buffer). We'll relex from that point. const char *StrData = Buffer.data() + LocInfo.second; const char *LexStart = findBeginningOfLine(Buffer, LocInfo.second); if (!LexStart || LexStart == StrData) return Loc; // Create a lexer starting at the beginning of this token. SourceLocation LexerStartLoc = Loc.getLocWithOffset(-LocInfo.second); Lexer TheLexer(LexerStartLoc, LangOpts, Buffer.data(), LexStart, Buffer.end()); TheLexer.SetCommentRetentionState(true); // Lex tokens until we find the token that contains the source location. Token TheTok; do { TheLexer.LexFromRawLexer(TheTok); if (TheLexer.getBufferLocation() > StrData) { // Lexing this token has taken the lexer past the source location we're // looking for. If the current token encompasses our source location, // return the beginning of that token. if (TheLexer.getBufferLocation() - TheTok.getLength() <= StrData) return TheTok.getLocation(); // We ended up skipping over the source location entirely, which means // that it points into whitespace. We're done here. break; } } while (TheTok.getKind() != tok::eof); // We've passed our source location; just return the original source location. return Loc; } SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts) { if (Loc.isFileID()) return getBeginningOfFileToken(Loc, SM, LangOpts); if (!SM.isMacroArgExpansion(Loc)) return Loc; SourceLocation FileLoc = SM.getSpellingLoc(Loc); SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts); std::pair FileLocInfo = SM.getDecomposedLoc(FileLoc); std::pair BeginFileLocInfo = SM.getDecomposedLoc(BeginFileLoc); assert(FileLocInfo.first == BeginFileLocInfo.first && FileLocInfo.second >= BeginFileLocInfo.second); return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second); } namespace { enum PreambleDirectiveKind { PDK_Skipped, PDK_StartIf, PDK_EndIf, PDK_Unknown }; } // end anonymous namespace std::pair Lexer::ComputePreamble(StringRef Buffer, const LangOptions &LangOpts, unsigned MaxLines) { // Create a lexer starting at the beginning of the file. Note that we use a // "fake" file source location at offset 1 so that the lexer will track our // position within the file. const unsigned StartOffset = 1; SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset); Lexer TheLexer(FileLoc, LangOpts, Buffer.begin(), Buffer.begin(), Buffer.end()); TheLexer.SetCommentRetentionState(true); // StartLoc will differ from FileLoc if there is a BOM that was skipped. SourceLocation StartLoc = TheLexer.getSourceLocation(); bool InPreprocessorDirective = false; Token TheTok; Token IfStartTok; unsigned IfCount = 0; SourceLocation ActiveCommentLoc; unsigned MaxLineOffset = 0; if (MaxLines) { const char *CurPtr = Buffer.begin(); unsigned CurLine = 0; while (CurPtr != Buffer.end()) { char ch = *CurPtr++; if (ch == '\n') { ++CurLine; if (CurLine == MaxLines) break; } } if (CurPtr != Buffer.end()) MaxLineOffset = CurPtr - Buffer.begin(); } do { TheLexer.LexFromRawLexer(TheTok); if (InPreprocessorDirective) { // If we've hit the end of the file, we're done. if (TheTok.getKind() == tok::eof) { break; } // If we haven't hit the end of the preprocessor directive, skip this // token. if (!TheTok.isAtStartOfLine()) continue; // We've passed the end of the preprocessor directive, and will look // at this token again below. InPreprocessorDirective = false; } // Keep track of the # of lines in the preamble. if (TheTok.isAtStartOfLine()) { unsigned TokOffset = TheTok.getLocation().getRawEncoding() - StartOffset; // If we were asked to limit the number of lines in the preamble, // and we're about to exceed that limit, we're done. if (MaxLineOffset && TokOffset >= MaxLineOffset) break; } // Comments are okay; skip over them. if (TheTok.getKind() == tok::comment) { if (ActiveCommentLoc.isInvalid()) ActiveCommentLoc = TheTok.getLocation(); continue; } if (TheTok.isAtStartOfLine() && TheTok.getKind() == tok::hash) { // This is the start of a preprocessor directive. Token HashTok = TheTok; InPreprocessorDirective = true; ActiveCommentLoc = SourceLocation(); // Figure out which directive this is. Since we're lexing raw tokens, // we don't have an identifier table available. Instead, just look at // the raw identifier to recognize and categorize preprocessor directives. TheLexer.LexFromRawLexer(TheTok); if (TheTok.getKind() == tok::raw_identifier && !TheTok.needsCleaning()) { StringRef Keyword = TheTok.getRawIdentifier(); PreambleDirectiveKind PDK = llvm::StringSwitch(Keyword) .Case("include", PDK_Skipped) .Case("__include_macros", PDK_Skipped) .Case("define", PDK_Skipped) .Case("undef", PDK_Skipped) .Case("line", PDK_Skipped) .Case("error", PDK_Skipped) .Case("pragma", PDK_Skipped) .Case("import", PDK_Skipped) .Case("include_next", PDK_Skipped) .Case("warning", PDK_Skipped) .Case("ident", PDK_Skipped) .Case("sccs", PDK_Skipped) .Case("assert", PDK_Skipped) .Case("unassert", PDK_Skipped) .Case("if", PDK_StartIf) .Case("ifdef", PDK_StartIf) .Case("ifndef", PDK_StartIf) .Case("elif", PDK_Skipped) .Case("else", PDK_Skipped) .Case("endif", PDK_EndIf) .Default(PDK_Unknown); switch (PDK) { case PDK_Skipped: continue; case PDK_StartIf: if (IfCount == 0) IfStartTok = HashTok; ++IfCount; continue; case PDK_EndIf: // Mismatched #endif. The preamble ends here. if (IfCount == 0) break; --IfCount; continue; case PDK_Unknown: // We don't know what this directive is; stop at the '#'. break; } } // We only end up here if we didn't recognize the preprocessor // directive or it was one that can't occur in the preamble at this // point. Roll back the current token to the location of the '#'. InPreprocessorDirective = false; TheTok = HashTok; } // We hit a token that we don't recognize as being in the // "preprocessing only" part of the file, so we're no longer in // the preamble. break; } while (true); SourceLocation End; if (IfCount) End = IfStartTok.getLocation(); else if (ActiveCommentLoc.isValid()) End = ActiveCommentLoc; // don't truncate a decl comment. else End = TheTok.getLocation(); return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(), IfCount? IfStartTok.isAtStartOfLine() : TheTok.isAtStartOfLine()); } /// AdvanceToTokenCharacter - Given a location that specifies the start of a /// token, return a new location that specifies a character within the token. SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart, unsigned CharNo, const SourceManager &SM, const LangOptions &LangOpts) { // Figure out how many physical characters away the specified expansion // character is. This needs to take into consideration newlines and // trigraphs. bool Invalid = false; const char *TokPtr = SM.getCharacterData(TokStart, &Invalid); // If they request the first char of the token, we're trivially done. if (Invalid || (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr))) return TokStart; unsigned PhysOffset = 0; // The usual case is that tokens don't contain anything interesting. Skip // over the uninteresting characters. If a token only consists of simple // chars, this method is extremely fast. while (Lexer::isObviouslySimpleCharacter(*TokPtr)) { if (CharNo == 0) return TokStart.getLocWithOffset(PhysOffset); ++TokPtr; --CharNo; ++PhysOffset; } // If we have a character that may be a trigraph or escaped newline, use a // lexer to parse it correctly. for (; CharNo; --CharNo) { unsigned Size; Lexer::getCharAndSizeNoWarn(TokPtr, Size, LangOpts); TokPtr += Size; PhysOffset += Size; } // Final detail: if we end up on an escaped newline, we want to return the // location of the actual byte of the token. For example foo\bar // advanced by 3 should return the location of b, not of \\. One compounding // detail of this is that the escape may be made by a trigraph. if (!Lexer::isObviouslySimpleCharacter(*TokPtr)) PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr; return TokStart.getLocWithOffset(PhysOffset); } /// \brief Computes the source location just past the end of the /// token at this source location. /// /// This routine can be used to produce a source location that /// points just past the end of the token referenced by \p Loc, and /// is generally used when a diagnostic needs to point just after a /// token where it expected something different that it received. If /// the returned source location would not be meaningful (e.g., if /// it points into a macro), this routine returns an invalid /// source location. /// /// \param Offset an offset from the end of the token, where the source /// location should refer to. The default offset (0) produces a source /// location pointing just past the end of the token; an offset of 1 produces /// a source location pointing to the last character in the token, etc. SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts) { if (Loc.isInvalid()) return SourceLocation(); if (Loc.isMacroID()) { if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc)) return SourceLocation(); // Points inside the macro expansion. } unsigned Len = Lexer::MeasureTokenLength(Loc, SM, LangOpts); if (Len > Offset) Len = Len - Offset; else return Loc; return Loc.getLocWithOffset(Len); } /// \brief Returns true if the given MacroID location points at the first /// token of the macro expansion. bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroBegin) { assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc"); SourceLocation expansionLoc; if (!SM.isAtStartOfImmediateMacroExpansion(loc, &expansionLoc)) return false; if (expansionLoc.isFileID()) { // No other macro expansions, this is the first. if (MacroBegin) *MacroBegin = expansionLoc; return true; } return isAtStartOfMacroExpansion(expansionLoc, SM, LangOpts, MacroBegin); } /// \brief Returns true if the given MacroID location points at the last /// token of the macro expansion. bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd) { assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc"); SourceLocation spellLoc = SM.getSpellingLoc(loc); unsigned tokLen = MeasureTokenLength(spellLoc, SM, LangOpts); if (tokLen == 0) return false; SourceLocation afterLoc = loc.getLocWithOffset(tokLen); SourceLocation expansionLoc; if (!SM.isAtEndOfImmediateMacroExpansion(afterLoc, &expansionLoc)) return false; if (expansionLoc.isFileID()) { // No other macro expansions. if (MacroEnd) *MacroEnd = expansionLoc; return true; } return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts, MacroEnd); } static CharSourceRange makeRangeFromFileLocs(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts) { SourceLocation Begin = Range.getBegin(); SourceLocation End = Range.getEnd(); assert(Begin.isFileID() && End.isFileID()); if (Range.isTokenRange()) { End = Lexer::getLocForEndOfToken(End, 0, SM,LangOpts); if (End.isInvalid()) return CharSourceRange(); } // Break down the source locations. FileID FID; unsigned BeginOffs; std::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin); if (FID.isInvalid()) return CharSourceRange(); unsigned EndOffs; if (!SM.isInFileID(End, FID, &EndOffs) || BeginOffs > EndOffs) return CharSourceRange(); return CharSourceRange::getCharRange(Begin, End); } CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts) { SourceLocation Begin = Range.getBegin(); SourceLocation End = Range.getEnd(); if (Begin.isInvalid() || End.isInvalid()) return CharSourceRange(); if (Begin.isFileID() && End.isFileID()) return makeRangeFromFileLocs(Range, SM, LangOpts); if (Begin.isMacroID() && End.isFileID()) { if (!isAtStartOfMacroExpansion(Begin, SM, LangOpts, &Begin)) return CharSourceRange(); Range.setBegin(Begin); return makeRangeFromFileLocs(Range, SM, LangOpts); } if (Begin.isFileID() && End.isMacroID()) { if ((Range.isTokenRange() && !isAtEndOfMacroExpansion(End, SM, LangOpts, &End)) || (Range.isCharRange() && !isAtStartOfMacroExpansion(End, SM, LangOpts, &End))) return CharSourceRange(); Range.setEnd(End); return makeRangeFromFileLocs(Range, SM, LangOpts); } assert(Begin.isMacroID() && End.isMacroID()); SourceLocation MacroBegin, MacroEnd; if (isAtStartOfMacroExpansion(Begin, SM, LangOpts, &MacroBegin) && ((Range.isTokenRange() && isAtEndOfMacroExpansion(End, SM, LangOpts, &MacroEnd)) || (Range.isCharRange() && isAtStartOfMacroExpansion(End, SM, LangOpts, &MacroEnd)))) { Range.setBegin(MacroBegin); Range.setEnd(MacroEnd); return makeRangeFromFileLocs(Range, SM, LangOpts); } bool Invalid = false; const SrcMgr::SLocEntry &BeginEntry = SM.getSLocEntry(SM.getFileID(Begin), &Invalid); if (Invalid) return CharSourceRange(); if (BeginEntry.getExpansion().isMacroArgExpansion()) { const SrcMgr::SLocEntry &EndEntry = SM.getSLocEntry(SM.getFileID(End), &Invalid); if (Invalid) return CharSourceRange(); if (EndEntry.getExpansion().isMacroArgExpansion() && BeginEntry.getExpansion().getExpansionLocStart() == EndEntry.getExpansion().getExpansionLocStart()) { Range.setBegin(SM.getImmediateSpellingLoc(Begin)); Range.setEnd(SM.getImmediateSpellingLoc(End)); return makeFileCharRange(Range, SM, LangOpts); } } return CharSourceRange(); } StringRef Lexer::getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid) { Range = makeFileCharRange(Range, SM, LangOpts); if (Range.isInvalid()) { if (Invalid) *Invalid = true; return StringRef(); } // Break down the source location. std::pair beginInfo = SM.getDecomposedLoc(Range.getBegin()); if (beginInfo.first.isInvalid()) { if (Invalid) *Invalid = true; return StringRef(); } unsigned EndOffs; if (!SM.isInFileID(Range.getEnd(), beginInfo.first, &EndOffs) || beginInfo.second > EndOffs) { if (Invalid) *Invalid = true; return StringRef(); } // Try to the load the file buffer. bool invalidTemp = false; StringRef file = SM.getBufferData(beginInfo.first, &invalidTemp); if (invalidTemp) { if (Invalid) *Invalid = true; return StringRef(); } if (Invalid) *Invalid = false; return file.substr(beginInfo.second, EndOffs - beginInfo.second); } StringRef Lexer::getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts) { assert(Loc.isMacroID() && "Only reasonble to call this on macros"); // Find the location of the immediate macro expansion. while (true) { FileID FID = SM.getFileID(Loc); const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID); const SrcMgr::ExpansionInfo &Expansion = E->getExpansion(); Loc = Expansion.getExpansionLocStart(); if (!Expansion.isMacroArgExpansion()) break; // For macro arguments we need to check that the argument did not come // from an inner macro, e.g: "MAC1( MAC2(foo) )" // Loc points to the argument id of the macro definition, move to the // macro expansion. Loc = SM.getImmediateExpansionRange(Loc).first; SourceLocation SpellLoc = Expansion.getSpellingLoc(); if (SpellLoc.isFileID()) break; // No inner macro. // If spelling location resides in the same FileID as macro expansion // location, it means there is no inner macro. FileID MacroFID = SM.getFileID(Loc); if (SM.isInFileID(SpellLoc, MacroFID)) break; // Argument came from inner macro. Loc = SpellLoc; } // Find the spelling location of the start of the non-argument expansion // range. This is where the macro name was spelled in order to begin // expanding this macro. Loc = SM.getSpellingLoc(Loc); // Dig out the buffer where the macro name was spelled and the extents of the // name so that we can render it into the expansion note. std::pair ExpansionInfo = SM.getDecomposedLoc(Loc); unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts); StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first); return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength); } StringRef Lexer::getImmediateMacroNameForDiagnostics( SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts) { assert(Loc.isMacroID() && "Only reasonble to call this on macros"); // Walk past macro argument expanions. while (SM.isMacroArgExpansion(Loc)) Loc = SM.getImmediateExpansionRange(Loc).first; // If the macro's spelling has no FileID, then it's actually a token paste // or stringization (or similar) and not a macro at all. if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc)))) return StringRef(); // Find the spelling location of the start of the non-argument expansion // range. This is where the macro name was spelled in order to begin // expanding this macro. Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first); // Dig out the buffer where the macro name was spelled and the extents of the // name so that we can render it into the expansion note. std::pair ExpansionInfo = SM.getDecomposedLoc(Loc); unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts); StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first); return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength); } bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) { return isIdentifierBody(c, LangOpts.DollarIdents); } StringRef Lexer::getIndentationForLine(SourceLocation Loc, const SourceManager &SM) { if (Loc.isInvalid() || Loc.isMacroID()) return ""; std::pair LocInfo = SM.getDecomposedLoc(Loc); if (LocInfo.first.isInvalid()) return ""; bool Invalid = false; StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) return ""; const char *Line = findBeginningOfLine(Buffer, LocInfo.second); if (!Line) return ""; StringRef Rest = Buffer.substr(Line - Buffer.data()); size_t NumWhitespaceChars = Rest.find_first_not_of(" \t"); return NumWhitespaceChars == StringRef::npos ? "" : Rest.take_front(NumWhitespaceChars); } //===----------------------------------------------------------------------===// // Diagnostics forwarding code. //===----------------------------------------------------------------------===// /// GetMappedTokenLoc - If lexing out of a 'mapped buffer', where we pretend the /// lexer buffer was all expanded at a single point, perform the mapping. /// This is currently only used for _Pragma implementation, so it is the slow /// path of the hot getSourceLocation method. Do not allow it to be inlined. static LLVM_ATTRIBUTE_NOINLINE SourceLocation GetMappedTokenLoc( Preprocessor &PP, SourceLocation FileLoc, unsigned CharNo, unsigned TokLen); static SourceLocation GetMappedTokenLoc(Preprocessor &PP, SourceLocation FileLoc, unsigned CharNo, unsigned TokLen) { assert(FileLoc.isMacroID() && "Must be a macro expansion"); // Otherwise, we're lexing "mapped tokens". This is used for things like // _Pragma handling. Combine the expansion location of FileLoc with the // spelling location. SourceManager &SM = PP.getSourceManager(); // Create a new SLoc which is expanded from Expansion(FileLoc) but whose // characters come from spelling(FileLoc)+Offset. SourceLocation SpellingLoc = SM.getSpellingLoc(FileLoc); SpellingLoc = SpellingLoc.getLocWithOffset(CharNo); // Figure out the expansion loc range, which is the range covered by the // original _Pragma(...) sequence. std::pair II = SM.getImmediateExpansionRange(FileLoc); return SM.createExpansionLoc(SpellingLoc, II.first, II.second, TokLen); } /// getSourceLocation - Return a source location identifier for the specified /// offset in the current file. SourceLocation Lexer::getSourceLocation(const char *Loc, unsigned TokLen) const { assert(Loc >= BufferStart && Loc <= BufferEnd && "Location out of range for this buffer!"); // In the normal case, we're just lexing from a simple file buffer, return // the file id from FileLoc with the offset specified. unsigned CharNo = Loc-BufferStart; if (FileLoc.isFileID()) return FileLoc.getLocWithOffset(CharNo); // Otherwise, this is the _Pragma lexer case, which pretends that all of the // tokens are lexed from where the _Pragma was defined. assert(PP && "This doesn't work on raw lexers"); return GetMappedTokenLoc(*PP, FileLoc, CharNo, TokLen); } /// Diag - Forwarding function for diagnostics. This translate a source /// position in the current buffer into a SourceLocation object for rendering. DiagnosticBuilder Lexer::Diag(const char *Loc, unsigned DiagID) const { return PP->Diag(getSourceLocation(Loc), DiagID); } //===----------------------------------------------------------------------===// // Trigraph and Escaped Newline Handling Code. //===----------------------------------------------------------------------===// /// GetTrigraphCharForLetter - Given a character that occurs after a ?? pair, /// return the decoded trigraph letter it corresponds to, or '\0' if nothing. static char GetTrigraphCharForLetter(char Letter) { switch (Letter) { default: return 0; case '=': return '#'; case ')': return ']'; case '(': return '['; case '!': return '|'; case '\'': return '^'; case '>': return '}'; case '/': return '\\'; case '<': return '{'; case '-': return '~'; } } /// DecodeTrigraphChar - If the specified character is a legal trigraph when /// prefixed with ??, emit a trigraph warning. If trigraphs are enabled, /// return the result character. Finally, emit a warning about trigraph use /// whether trigraphs are enabled or not. static char DecodeTrigraphChar(const char *CP, Lexer *L) { char Res = GetTrigraphCharForLetter(*CP); if (!Res || !L) return Res; if (!L->getLangOpts().Trigraphs) { if (!L->isLexingRawMode()) L->Diag(CP-2, diag::trigraph_ignored); return 0; } if (!L->isLexingRawMode()) L->Diag(CP-2, diag::trigraph_converted) << StringRef(&Res, 1); return Res; } /// getEscapedNewLineSize - Return the size of the specified escaped newline, /// or 0 if it is not an escaped newline. P[-1] is known to be a "\" or a /// trigraph equivalent on entry to this function. unsigned Lexer::getEscapedNewLineSize(const char *Ptr) { unsigned Size = 0; while (isWhitespace(Ptr[Size])) { ++Size; if (Ptr[Size-1] != '\n' && Ptr[Size-1] != '\r') continue; // If this is a \r\n or \n\r, skip the other half. if ((Ptr[Size] == '\r' || Ptr[Size] == '\n') && Ptr[Size-1] != Ptr[Size]) ++Size; return Size; } // Not an escaped newline, must be a \t or something else. return 0; } /// SkipEscapedNewLines - If P points to an escaped newline (or a series of /// them), skip over them and return the first non-escaped-newline found, /// otherwise return P. const char *Lexer::SkipEscapedNewLines(const char *P) { while (true) { const char *AfterEscape; if (*P == '\\') { AfterEscape = P+1; } else if (*P == '?') { // If not a trigraph for escape, bail out. if (P[1] != '?' || P[2] != '/') return P; // FIXME: Take LangOpts into account; the language might not // support trigraphs. AfterEscape = P+3; } else { return P; } unsigned NewLineSize = Lexer::getEscapedNewLineSize(AfterEscape); if (NewLineSize == 0) return P; P = AfterEscape+NewLineSize; } } /// \brief Checks that the given token is the first token that occurs after the /// given location (this excludes comments and whitespace). Returns the location /// immediately after the specified token. If the token is not found or the /// location is inside a macro, the returned source location will be invalid. SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc, tok::TokenKind TKind, const SourceManager &SM, const LangOptions &LangOpts, bool SkipTrailingWhitespaceAndNewLine) { if (Loc.isMacroID()) { if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc)) return SourceLocation(); } Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); // Break down the source location. std::pair LocInfo = SM.getDecomposedLoc(Loc); // Try to load the file buffer. bool InvalidTemp = false; StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp); if (InvalidTemp) return SourceLocation(); const char *TokenBegin = File.data() + LocInfo.second; // Lex from the start of the given location. Lexer lexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(), TokenBegin, File.end()); // Find the token. Token Tok; lexer.LexFromRawLexer(Tok); if (Tok.isNot(TKind)) return SourceLocation(); SourceLocation TokenLoc = Tok.getLocation(); // Calculate how much whitespace needs to be skipped if any. unsigned NumWhitespaceChars = 0; if (SkipTrailingWhitespaceAndNewLine) { const char *TokenEnd = SM.getCharacterData(TokenLoc) + Tok.getLength(); unsigned char C = *TokenEnd; while (isHorizontalWhitespace(C)) { C = *(++TokenEnd); NumWhitespaceChars++; } // Skip \r, \n, \r\n, or \n\r if (C == '\n' || C == '\r') { char PrevC = C; C = *(++TokenEnd); NumWhitespaceChars++; if ((C == '\n' || C == '\r') && C != PrevC) NumWhitespaceChars++; } } return TokenLoc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars); } /// getCharAndSizeSlow - Peek a single 'character' from the specified buffer, /// get its size, and return it. This is tricky in several cases: /// 1. If currently at the start of a trigraph, we warn about the trigraph, /// then either return the trigraph (skipping 3 chars) or the '?', /// depending on whether trigraphs are enabled or not. /// 2. If this is an escaped newline (potentially with whitespace between /// the backslash and newline), implicitly skip the newline and return /// the char after it. /// /// This handles the slow/uncommon case of the getCharAndSize method. Here we /// know that we can accumulate into Size, and that we have already incremented /// Ptr by Size bytes. /// /// NOTE: When this method is updated, getCharAndSizeSlowNoWarn (below) should /// be updated to match. /// char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size, Token *Tok) { // If we have a slash, look for an escaped newline. if (Ptr[0] == '\\') { ++Size; ++Ptr; Slash: // Common case, backslash-char where the char is not whitespace. if (!isWhitespace(Ptr[0])) return '\\'; // See if we have optional whitespace characters between the slash and // newline. if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) { // Remember that this token needs to be cleaned. if (Tok) Tok->setFlag(Token::NeedsCleaning); // Warn if there was whitespace between the backslash and newline. if (Ptr[0] != '\n' && Ptr[0] != '\r' && Tok && !isLexingRawMode()) Diag(Ptr, diag::backslash_newline_space); // Found backslash. Parse the char after it. Size += EscapedNewLineSize; Ptr += EscapedNewLineSize; // Use slow version to accumulate a correct size field. return getCharAndSizeSlow(Ptr, Size, Tok); } // Otherwise, this is not an escaped newline, just return the slash. return '\\'; } // If this is a trigraph, process it. if (Ptr[0] == '?' && Ptr[1] == '?') { // If this is actually a legal trigraph (not something like "??x"), emit // a trigraph warning. If so, and if trigraphs are enabled, return it. if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : nullptr)) { // Remember that this token needs to be cleaned. if (Tok) Tok->setFlag(Token::NeedsCleaning); Ptr += 3; Size += 3; if (C == '\\') goto Slash; return C; } } // If this is neither, return a single character. ++Size; return *Ptr; } /// getCharAndSizeSlowNoWarn - Handle the slow/uncommon case of the /// getCharAndSizeNoWarn method. Here we know that we can accumulate into Size, /// and that we have already incremented Ptr by Size bytes. /// /// NOTE: When this method is updated, getCharAndSizeSlow (above) should /// be updated to match. char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size, const LangOptions &LangOpts) { // If we have a slash, look for an escaped newline. if (Ptr[0] == '\\') { ++Size; ++Ptr; Slash: // Common case, backslash-char where the char is not whitespace. if (!isWhitespace(Ptr[0])) return '\\'; // See if we have optional whitespace characters followed by a newline. if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) { // Found backslash. Parse the char after it. Size += EscapedNewLineSize; Ptr += EscapedNewLineSize; // Use slow version to accumulate a correct size field. return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts); } // Otherwise, this is not an escaped newline, just return the slash. return '\\'; } // If this is a trigraph, process it. if (LangOpts.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') { // If this is actually a legal trigraph (not something like "??x"), return // it. if (char C = GetTrigraphCharForLetter(Ptr[2])) { Ptr += 3; Size += 3; if (C == '\\') goto Slash; return C; } } // If this is neither, return a single character. ++Size; return *Ptr; } //===----------------------------------------------------------------------===// // Helper methods for lexing. //===----------------------------------------------------------------------===// /// \brief Routine that indiscriminately skips bytes in the source file. void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) { BufferPtr += Bytes; if (BufferPtr > BufferEnd) BufferPtr = BufferEnd; // FIXME: What exactly does the StartOfLine bit mean? There are two // possible meanings for the "start" of the line: the first token on the // unexpanded line, or the first token on the expanded line. IsAtStartOfLine = StartOfLine; IsAtPhysicalStartOfLine = StartOfLine; } static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) { if (LangOpts.AsmPreprocessor) { return false; } else if (LangOpts.CPlusPlus11 || LangOpts.C11) { static const llvm::sys::UnicodeCharSet C11AllowedIDChars( C11AllowedIDCharRanges); return C11AllowedIDChars.contains(C); } else if (LangOpts.CPlusPlus) { static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars( CXX03AllowedIDCharRanges); return CXX03AllowedIDChars.contains(C); } else { static const llvm::sys::UnicodeCharSet C99AllowedIDChars( C99AllowedIDCharRanges); return C99AllowedIDChars.contains(C); } } static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) { assert(isAllowedIDChar(C, LangOpts)); if (LangOpts.AsmPreprocessor) { return false; } else if (LangOpts.CPlusPlus11 || LangOpts.C11) { static const llvm::sys::UnicodeCharSet C11DisallowedInitialIDChars( C11DisallowedInitialIDCharRanges); return !C11DisallowedInitialIDChars.contains(C); } else if (LangOpts.CPlusPlus) { return true; } else { static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars( C99DisallowedInitialIDCharRanges); return !C99DisallowedInitialIDChars.contains(C); } } static inline CharSourceRange makeCharRange(Lexer &L, const char *Begin, const char *End) { return CharSourceRange::getCharRange(L.getSourceLocation(Begin), L.getSourceLocation(End)); } static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C, CharSourceRange Range, bool IsFirst) { // Check C99 compatibility. if (!Diags.isIgnored(diag::warn_c99_compat_unicode_id, Range.getBegin())) { enum { CannotAppearInIdentifier = 0, CannotStartIdentifier }; static const llvm::sys::UnicodeCharSet C99AllowedIDChars( C99AllowedIDCharRanges); static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars( C99DisallowedInitialIDCharRanges); if (!C99AllowedIDChars.contains(C)) { Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id) << Range << CannotAppearInIdentifier; } else if (IsFirst && C99DisallowedInitialIDChars.contains(C)) { Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id) << Range << CannotStartIdentifier; } } // Check C++98 compatibility. if (!Diags.isIgnored(diag::warn_cxx98_compat_unicode_id, Range.getBegin())) { static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars( CXX03AllowedIDCharRanges); if (!CXX03AllowedIDChars.contains(C)) { Diags.Report(Range.getBegin(), diag::warn_cxx98_compat_unicode_id) << Range; } } } bool Lexer::tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size, Token &Result) { const char *UCNPtr = CurPtr + Size; uint32_t CodePoint = tryReadUCN(UCNPtr, CurPtr, /*Token=*/nullptr); if (CodePoint == 0 || !isAllowedIDChar(CodePoint, LangOpts)) return false; if (!isLexingRawMode()) maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint, makeCharRange(*this, CurPtr, UCNPtr), /*IsFirst=*/false); Result.setFlag(Token::HasUCN); if ((UCNPtr - CurPtr == 6 && CurPtr[1] == 'u') || (UCNPtr - CurPtr == 10 && CurPtr[1] == 'U')) CurPtr = UCNPtr; else while (CurPtr != UCNPtr) (void)getAndAdvanceChar(CurPtr, Result); return true; } bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) { const char *UnicodePtr = CurPtr; llvm::UTF32 CodePoint; llvm::ConversionResult Result = llvm::convertUTF8Sequence((const llvm::UTF8 **)&UnicodePtr, (const llvm::UTF8 *)BufferEnd, &CodePoint, llvm::strictConversion); if (Result != llvm::conversionOK || !isAllowedIDChar(static_cast(CodePoint), LangOpts)) return false; if (!isLexingRawMode()) maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint, makeCharRange(*this, CurPtr, UnicodePtr), /*IsFirst=*/false); CurPtr = UnicodePtr; return true; } bool Lexer::LexIdentifier(Token &Result, const char *CurPtr) { // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$] unsigned Size; unsigned char C = *CurPtr++; while (isIdentifierBody(C)) C = *CurPtr++; --CurPtr; // Back up over the skipped character. // Fast path, no $,\,? in identifier found. '\' might be an escaped newline // or UCN, and ? might be a trigraph for '\', an escaped newline or UCN. // // TODO: Could merge these checks into an InfoTable flag to make the // comparison cheaper if (isASCII(C) && C != '\\' && C != '?' && (C != '$' || !LangOpts.DollarIdents)) { FinishIdentifier: const char *IdStart = BufferPtr; FormTokenWithChars(Result, CurPtr, tok::raw_identifier); Result.setRawIdentifierData(IdStart); // If we are in raw mode, return this identifier raw. There is no need to // look up identifier information or attempt to macro expand it. if (LexingRawMode) return true; // Fill in Result.IdentifierInfo and update the token kind, // looking up the identifier in the identifier table. IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); // Finally, now that we know we have an identifier, pass this off to the // preprocessor, which may macro expand it or something. if (II->isHandleIdentifierCase()) return PP->HandleIdentifier(Result); if (II->getTokenID() == tok::identifier && isCodeCompletionPoint(CurPtr) && II->getPPKeywordID() == tok::pp_not_keyword && II->getObjCKeywordID() == tok::objc_not_keyword) { // Return the code-completion token. Result.setKind(tok::code_completion); cutOffLexing(); return true; } return true; } // Otherwise, $,\,? in identifier found. Enter slower path. C = getCharAndSize(CurPtr, Size); while (true) { if (C == '$') { // If we hit a $ and they are not supported in identifiers, we are done. if (!LangOpts.DollarIdents) goto FinishIdentifier; // Otherwise, emit a diagnostic and continue. if (!isLexingRawMode()) Diag(CurPtr, diag::ext_dollar_in_identifier); CurPtr = ConsumeChar(CurPtr, Size, Result); C = getCharAndSize(CurPtr, Size); continue; } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) { C = getCharAndSize(CurPtr, Size); continue; } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) { C = getCharAndSize(CurPtr, Size); continue; } else if (!isIdentifierBody(C)) { goto FinishIdentifier; } // Otherwise, this character is good, consume it. CurPtr = ConsumeChar(CurPtr, Size, Result); C = getCharAndSize(CurPtr, Size); while (isIdentifierBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result); C = getCharAndSize(CurPtr, Size); } } } /// isHexaLiteral - Return true if Start points to a hex constant. /// in microsoft mode (where this is supposed to be several different tokens). bool Lexer::isHexaLiteral(const char *Start, const LangOptions &LangOpts) { unsigned Size; char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, LangOpts); if (C1 != '0') return false; char C2 = Lexer::getCharAndSizeNoWarn(Start + Size, Size, LangOpts); return (C2 == 'x' || C2 == 'X'); } /// LexNumericConstant - Lex the remainder of a integer or floating point /// constant. From[-1] is the first character lexed. Return the end of the /// constant. bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { unsigned Size; char C = getCharAndSize(CurPtr, Size); char PrevCh = 0; while (isPreprocessingNumberBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result); PrevCh = C; C = getCharAndSize(CurPtr, Size); } // If we fell out, check for a sign, due to 1e+12. If we have one, continue. if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) { // If we are in Microsoft mode, don't continue if the constant is hex. // For example, MSVC will accept the following as 3 tokens: 0x1234567e+1 if (!LangOpts.MicrosoftExt || !isHexaLiteral(BufferPtr, LangOpts)) return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); } // If we have a hex FP constant, continue. if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p')) { // Outside C99 and C++17, we accept hexadecimal floating point numbers as a // not-quite-conforming extension. Only do so if this looks like it's // actually meant to be a hexfloat, and not if it has a ud-suffix. bool IsHexFloat = true; if (!LangOpts.C99) { if (!isHexaLiteral(BufferPtr, LangOpts)) IsHexFloat = false; else if (!getLangOpts().CPlusPlus1z && std::find(BufferPtr, CurPtr, '_') != CurPtr) IsHexFloat = false; } if (IsHexFloat) return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); } // If we have a digit separator, continue. if (C == '\'' && getLangOpts().CPlusPlus14) { unsigned NextSize; char Next = getCharAndSizeNoWarn(CurPtr + Size, NextSize, getLangOpts()); if (isIdentifierBody(Next)) { if (!isLexingRawMode()) Diag(CurPtr, diag::warn_cxx11_compat_digit_separator); CurPtr = ConsumeChar(CurPtr, Size, Result); CurPtr = ConsumeChar(CurPtr, NextSize, Result); return LexNumericConstant(Result, CurPtr); } } // If we have a UCN or UTF-8 character (perhaps in a ud-suffix), continue. if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) return LexNumericConstant(Result, CurPtr); if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) return LexNumericConstant(Result, CurPtr); // Update the location of token as well as BufferPtr. const char *TokStart = BufferPtr; FormTokenWithChars(Result, CurPtr, tok::numeric_constant); Result.setLiteralData(TokStart); return true; } /// LexUDSuffix - Lex the ud-suffix production for user-defined literal suffixes /// in C++11, or warn on a ud-suffix in C++98. const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr, bool IsStringLiteral) { assert(getLangOpts().CPlusPlus); // Maximally munch an identifier. unsigned Size; char C = getCharAndSize(CurPtr, Size); bool Consumed = false; if (!isIdentifierHead(C)) { if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) Consumed = true; else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) Consumed = true; else return CurPtr; } if (!getLangOpts().CPlusPlus11) { if (!isLexingRawMode()) Diag(CurPtr, C == '_' ? diag::warn_cxx11_compat_user_defined_literal : diag::warn_cxx11_compat_reserved_user_defined_literal) << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); return CurPtr; } // C++11 [lex.ext]p10, [usrlit.suffix]p1: A program containing a ud-suffix // that does not start with an underscore is ill-formed. As a conforming // extension, we treat all such suffixes as if they had whitespace before // them. We assume a suffix beginning with a UCN or UTF-8 character is more // likely to be a ud-suffix than a macro, however, and accept that. if (!Consumed) { bool IsUDSuffix = false; if (C == '_') IsUDSuffix = true; else if (IsStringLiteral && getLangOpts().CPlusPlus14) { // In C++1y, we need to look ahead a few characters to see if this is a // valid suffix for a string literal or a numeric literal (this could be // the 'operator""if' defining a numeric literal operator). const unsigned MaxStandardSuffixLength = 3; char Buffer[MaxStandardSuffixLength] = { C }; unsigned Consumed = Size; unsigned Chars = 1; while (true) { unsigned NextSize; char Next = getCharAndSizeNoWarn(CurPtr + Consumed, NextSize, getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. const StringRef CompleteSuffix(Buffer, Chars); IsUDSuffix = StringLiteralParser::isValidUDSuffix(getLangOpts(), CompleteSuffix); break; } if (Chars == MaxStandardSuffixLength) // Too long: can't be a standard suffix. break; Buffer[Chars++] = Next; Consumed += NextSize; } } if (!IsUDSuffix) { if (!isLexingRawMode()) Diag(CurPtr, getLangOpts().MSVCCompat ? diag::ext_ms_reserved_user_defined_literal : diag::ext_reserved_user_defined_literal) << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); return CurPtr; } CurPtr = ConsumeChar(CurPtr, Size, Result); } Result.setFlag(Token::HasUDSuffix); while (true) { C = getCharAndSize(CurPtr, Size); if (isIdentifierBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result); } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) {} else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) {} else break; } return CurPtr; } /// LexStringLiteral - Lex the remainder of a string literal, after having lexed /// either " or L" or u8" or u" or U". bool Lexer::LexStringLiteral(Token &Result, const char *CurPtr, tok::TokenKind Kind) { // Does this string contain the \0 character? const char *NulCharacter = nullptr; if (!isLexingRawMode() && (Kind == tok::utf8_string_literal || Kind == tok::utf16_string_literal || Kind == tok::utf32_string_literal)) Diag(BufferPtr, getLangOpts().CPlusPlus ? diag::warn_cxx98_compat_unicode_literal : diag::warn_c99_compat_unicode_literal); char C = getAndAdvanceChar(CurPtr, Result); while (C != '"') { // Skip escaped characters. Escaped newlines will already be processed by // getAndAdvanceChar. if (C == '\\') C = getAndAdvanceChar(CurPtr, Result); if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. if (!isLexingRawMode() && !LangOpts.AsmPreprocessor) Diag(BufferPtr, diag::ext_unterminated_char_or_string) << 1; FormTokenWithChars(Result, CurPtr-1, tok::unknown); return true; } if (C == 0) { if (isCodeCompletionPoint(CurPtr-1)) { PP->CodeCompleteNaturalLanguage(); FormTokenWithChars(Result, CurPtr-1, tok::unknown); cutOffLexing(); return true; } NulCharacter = CurPtr-1; } C = getAndAdvanceChar(CurPtr, Result); } // If we are in C++11, lex the optional ud-suffix. if (getLangOpts().CPlusPlus) CurPtr = LexUDSuffix(Result, CurPtr, true); // If a nul character existed in the string, warn about it. if (NulCharacter && !isLexingRawMode()) Diag(NulCharacter, diag::null_in_char_or_string) << 1; // Update the location of the token as well as the BufferPtr instance var. const char *TokStart = BufferPtr; FormTokenWithChars(Result, CurPtr, Kind); Result.setLiteralData(TokStart); return true; } /// LexRawStringLiteral - Lex the remainder of a raw string literal, after /// having lexed R", LR", u8R", uR", or UR". bool Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr, tok::TokenKind Kind) { // This function doesn't use getAndAdvanceChar because C++0x [lex.pptoken]p3: // Between the initial and final double quote characters of the raw string, // any transformations performed in phases 1 and 2 (trigraphs, // universal-character-names, and line splicing) are reverted. if (!isLexingRawMode()) Diag(BufferPtr, diag::warn_cxx98_compat_raw_string_literal); unsigned PrefixLen = 0; while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen])) ++PrefixLen; // If the last character was not a '(', then we didn't lex a valid delimiter. if (CurPtr[PrefixLen] != '(') { if (!isLexingRawMode()) { const char *PrefixEnd = &CurPtr[PrefixLen]; if (PrefixLen == 16) { Diag(PrefixEnd, diag::err_raw_delim_too_long); } else { Diag(PrefixEnd, diag::err_invalid_char_raw_delim) << StringRef(PrefixEnd, 1); } } // Search for the next '"' in hopes of salvaging the lexer. Unfortunately, // it's possible the '"' was intended to be part of the raw string, but // there's not much we can do about that. while (true) { char C = *CurPtr++; if (C == '"') break; if (C == 0 && CurPtr-1 == BufferEnd) { --CurPtr; break; } } FormTokenWithChars(Result, CurPtr, tok::unknown); return true; } // Save prefix and move CurPtr past it const char *Prefix = CurPtr; CurPtr += PrefixLen + 1; // skip over prefix and '(' while (true) { char C = *CurPtr++; if (C == ')') { // Check for prefix match and closing quote. if (strncmp(CurPtr, Prefix, PrefixLen) == 0 && CurPtr[PrefixLen] == '"') { CurPtr += PrefixLen + 1; // skip over prefix and '"' break; } } else if (C == 0 && CurPtr-1 == BufferEnd) { // End of file. if (!isLexingRawMode()) Diag(BufferPtr, diag::err_unterminated_raw_string) << StringRef(Prefix, PrefixLen); FormTokenWithChars(Result, CurPtr-1, tok::unknown); return true; } } // If we are in C++11, lex the optional ud-suffix. if (getLangOpts().CPlusPlus) CurPtr = LexUDSuffix(Result, CurPtr, true); // Update the location of token as well as BufferPtr. const char *TokStart = BufferPtr; FormTokenWithChars(Result, CurPtr, Kind); Result.setLiteralData(TokStart); return true; } /// LexAngledStringLiteral - Lex the remainder of an angled string literal, /// after having lexed the '<' character. This is used for #include filenames. bool Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) { // Does this string contain the \0 character? const char *NulCharacter = nullptr; const char *AfterLessPos = CurPtr; char C = getAndAdvanceChar(CurPtr, Result); while (C != '>') { // Skip escaped characters. if (C == '\\' && CurPtr < BufferEnd) { // Skip the escaped character. getAndAdvanceChar(CurPtr, Result); } else if (C == '\n' || C == '\r' || // Newline. (C == 0 && (CurPtr-1 == BufferEnd || // End of file. isCodeCompletionPoint(CurPtr-1)))) { // If the filename is unterminated, then it must just be a lone < // character. Return this as such. FormTokenWithChars(Result, AfterLessPos, tok::less); return true; } else if (C == 0) { NulCharacter = CurPtr-1; } C = getAndAdvanceChar(CurPtr, Result); } // If a nul character existed in the string, warn about it. if (NulCharacter && !isLexingRawMode()) Diag(NulCharacter, diag::null_in_char_or_string) << 1; // Update the location of token as well as BufferPtr. const char *TokStart = BufferPtr; FormTokenWithChars(Result, CurPtr, tok::angle_string_literal); Result.setLiteralData(TokStart); return true; } /// LexCharConstant - Lex the remainder of a character constant, after having /// lexed either ' or L' or u8' or u' or U'. bool Lexer::LexCharConstant(Token &Result, const char *CurPtr, tok::TokenKind Kind) { // Does this character contain the \0 character? const char *NulCharacter = nullptr; if (!isLexingRawMode()) { if (Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant) Diag(BufferPtr, getLangOpts().CPlusPlus ? diag::warn_cxx98_compat_unicode_literal : diag::warn_c99_compat_unicode_literal); else if (Kind == tok::utf8_char_constant) Diag(BufferPtr, diag::warn_cxx14_compat_u8_character_literal); } char C = getAndAdvanceChar(CurPtr, Result); if (C == '\'') { if (!isLexingRawMode() && !LangOpts.AsmPreprocessor) Diag(BufferPtr, diag::ext_empty_character); FormTokenWithChars(Result, CurPtr, tok::unknown); return true; } while (C != '\'') { // Skip escaped characters. if (C == '\\') C = getAndAdvanceChar(CurPtr, Result); if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. if (!isLexingRawMode() && !LangOpts.AsmPreprocessor) Diag(BufferPtr, diag::ext_unterminated_char_or_string) << 0; FormTokenWithChars(Result, CurPtr-1, tok::unknown); return true; } if (C == 0) { if (isCodeCompletionPoint(CurPtr-1)) { PP->CodeCompleteNaturalLanguage(); FormTokenWithChars(Result, CurPtr-1, tok::unknown); cutOffLexing(); return true; } NulCharacter = CurPtr-1; } C = getAndAdvanceChar(CurPtr, Result); } // If we are in C++11, lex the optional ud-suffix. if (getLangOpts().CPlusPlus) CurPtr = LexUDSuffix(Result, CurPtr, false); // If a nul character existed in the character, warn about it. if (NulCharacter && !isLexingRawMode()) Diag(NulCharacter, diag::null_in_char_or_string) << 0; // Update the location of token as well as BufferPtr. const char *TokStart = BufferPtr; FormTokenWithChars(Result, CurPtr, Kind); Result.setLiteralData(TokStart); return true; } /// SkipWhitespace - Efficiently skip over a series of whitespace characters. /// Update BufferPtr to point to the next non-whitespace character and return. /// /// This method forms a token and returns true if KeepWhitespaceMode is enabled. /// bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr, bool &TokAtPhysicalStartOfLine) { // Whitespace - Skip it, then return the token after the whitespace. bool SawNewline = isVerticalWhitespace(CurPtr[-1]); unsigned char Char = *CurPtr; // Skip consecutive spaces efficiently. while (true) { // Skip horizontal whitespace very aggressively. while (isHorizontalWhitespace(Char)) Char = *++CurPtr; // Otherwise if we have something other than whitespace, we're done. if (!isVerticalWhitespace(Char)) break; if (ParsingPreprocessorDirective) { // End of preprocessor directive line, let LexTokenInternal handle this. BufferPtr = CurPtr; return false; } // OK, but handle newline. SawNewline = true; Char = *++CurPtr; } // If the client wants us to return whitespace, return it now. if (isKeepWhitespaceMode()) { FormTokenWithChars(Result, CurPtr, tok::unknown); if (SawNewline) { IsAtStartOfLine = true; IsAtPhysicalStartOfLine = true; } // FIXME: The next token will not have LeadingSpace set. return true; } // If this isn't immediately after a newline, there is leading space. char PrevChar = CurPtr[-1]; bool HasLeadingSpace = !isVerticalWhitespace(PrevChar); Result.setFlagValue(Token::LeadingSpace, HasLeadingSpace); if (SawNewline) { Result.setFlag(Token::StartOfLine); TokAtPhysicalStartOfLine = true; } BufferPtr = CurPtr; return false; } /// We have just read the // characters from input. Skip until we find the /// newline character thats terminate the comment. Then update BufferPtr and /// return. /// /// If we're in KeepCommentMode or any CommentHandler has inserted /// some tokens, this will store the first token and return true. bool Lexer::SkipLineComment(Token &Result, const char *CurPtr, bool &TokAtPhysicalStartOfLine) { // If Line comments aren't explicitly enabled for this language, emit an // extension warning. if (!LangOpts.LineComment && !isLexingRawMode()) { Diag(BufferPtr, diag::ext_line_comment); // Mark them enabled so we only emit one warning for this translation // unit. LangOpts.LineComment = true; } // Scan over the body of the comment. The common case, when scanning, is that // the comment contains normal ascii characters with nothing interesting in // them. As such, optimize for this case with the inner loop. // // This loop terminates with CurPtr pointing at the newline (or end of buffer) // character that ends the line comment. char C; while (true) { C = *CurPtr; // Skip over characters in the fast loop. while (C != 0 && // Potentially EOF. C != '\n' && C != '\r') // Newline or DOS-style newline. C = *++CurPtr; const char *NextLine = CurPtr; if (C != 0) { // We found a newline, see if it's escaped. const char *EscapePtr = CurPtr-1; bool HasSpace = false; while (isHorizontalWhitespace(*EscapePtr)) { // Skip whitespace. --EscapePtr; HasSpace = true; } if (*EscapePtr == '\\') // Escaped newline. CurPtr = EscapePtr; else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' && EscapePtr[-2] == '?' && LangOpts.Trigraphs) // Trigraph-escaped newline. CurPtr = EscapePtr-2; else break; // This is a newline, we're done. // If there was space between the backslash and newline, warn about it. if (HasSpace && !isLexingRawMode()) Diag(EscapePtr, diag::backslash_newline_space); } // Otherwise, this is a hard case. Fall back on getAndAdvanceChar to // properly decode the character. Read it in raw mode to avoid emitting // diagnostics about things like trigraphs. If we see an escaped newline, // we'll handle it below. const char *OldPtr = CurPtr; bool OldRawMode = isLexingRawMode(); LexingRawMode = true; C = getAndAdvanceChar(CurPtr, Result); LexingRawMode = OldRawMode; // If we only read only one character, then no special handling is needed. // We're done and can skip forward to the newline. if (C != 0 && CurPtr == OldPtr+1) { CurPtr = NextLine; break; } // If we read multiple characters, and one of those characters was a \r or // \n, then we had an escaped newline within the comment. Emit diagnostic // unless the next line is also a // comment. if (CurPtr != OldPtr+1 && C != '/' && CurPtr[0] != '/') { for (; OldPtr != CurPtr; ++OldPtr) if (OldPtr[0] == '\n' || OldPtr[0] == '\r') { // Okay, we found a // comment that ends in a newline, if the next // line is also a // comment, but has spaces, don't emit a diagnostic. if (isWhitespace(C)) { const char *ForwardPtr = CurPtr; while (isWhitespace(*ForwardPtr)) // Skip whitespace. ++ForwardPtr; if (ForwardPtr[0] == '/' && ForwardPtr[1] == '/') break; } if (!isLexingRawMode()) Diag(OldPtr-1, diag::ext_multi_line_line_comment); break; } } if (C == '\r' || C == '\n' || CurPtr == BufferEnd + 1) { --CurPtr; break; } if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) { PP->CodeCompleteNaturalLanguage(); cutOffLexing(); return false; } } // Found but did not consume the newline. Notify comment handlers about the // comment unless we're in a #if 0 block. if (PP && !isLexingRawMode() && PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr), getSourceLocation(CurPtr)))) { BufferPtr = CurPtr; return true; // A token has to be returned. } // If we are returning comments as tokens, return this comment as a token. if (inKeepCommentMode()) return SaveLineComment(Result, CurPtr); // If we are inside a preprocessor directive and we see the end of line, // return immediately, so that the lexer can return this as an EOD token. if (ParsingPreprocessorDirective || CurPtr == BufferEnd) { BufferPtr = CurPtr; return false; } // Otherwise, eat the \n character. We don't care if this is a \n\r or // \r\n sequence. This is an efficiency hack (because we know the \n can't // contribute to another token), it isn't needed for correctness. Note that // this is ok even in KeepWhitespaceMode, because we would have returned the /// comment above in that mode. ++CurPtr; // The next returned token is at the start of the line. Result.setFlag(Token::StartOfLine); TokAtPhysicalStartOfLine = true; // No leading whitespace seen so far. Result.clearFlag(Token::LeadingSpace); BufferPtr = CurPtr; return false; } /// If in save-comment mode, package up this Line comment in an appropriate /// way and return it. bool Lexer::SaveLineComment(Token &Result, const char *CurPtr) { // If we're not in a preprocessor directive, just return the // comment // directly. FormTokenWithChars(Result, CurPtr, tok::comment); if (!ParsingPreprocessorDirective || LexingRawMode) return true; // If this Line-style comment is in a macro definition, transmogrify it into // a C-style block comment. bool Invalid = false; std::string Spelling = PP->getSpelling(Result, &Invalid); if (Invalid) return true; assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not line comment?"); Spelling[1] = '*'; // Change prefix to "/*". Spelling += "*/"; // add suffix. Result.setKind(tok::comment); PP->CreateString(Spelling, Result, Result.getLocation(), Result.getLocation()); return true; } /// isBlockCommentEndOfEscapedNewLine - Return true if the specified newline /// character (either \\n or \\r) is part of an escaped newline sequence. Issue /// a diagnostic if so. We know that the newline is inside of a block comment. static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr, Lexer *L) { assert(CurPtr[0] == '\n' || CurPtr[0] == '\r'); // Back up off the newline. --CurPtr; // If this is a two-character newline sequence, skip the other character. if (CurPtr[0] == '\n' || CurPtr[0] == '\r') { // \n\n or \r\r -> not escaped newline. if (CurPtr[0] == CurPtr[1]) return false; // \n\r or \r\n -> skip the newline. --CurPtr; } // If we have horizontal whitespace, skip over it. We allow whitespace // between the slash and newline. bool HasSpace = false; while (isHorizontalWhitespace(*CurPtr) || *CurPtr == 0) { --CurPtr; HasSpace = true; } // If we have a slash, we know this is an escaped newline. if (*CurPtr == '\\') { if (CurPtr[-1] != '*') return false; } else { // It isn't a slash, is it the ?? / trigraph? if (CurPtr[0] != '/' || CurPtr[-1] != '?' || CurPtr[-2] != '?' || CurPtr[-3] != '*') return false; // This is the trigraph ending the comment. Emit a stern warning! CurPtr -= 2; // If no trigraphs are enabled, warn that we ignored this trigraph and // ignore this * character. if (!L->getLangOpts().Trigraphs) { if (!L->isLexingRawMode()) L->Diag(CurPtr, diag::trigraph_ignored_block_comment); return false; } if (!L->isLexingRawMode()) L->Diag(CurPtr, diag::trigraph_ends_block_comment); } // Warn about having an escaped newline between the */ characters. if (!L->isLexingRawMode()) L->Diag(CurPtr, diag::escaped_newline_block_comment_end); // If there was space between the backslash and newline, warn about it. if (HasSpace && !L->isLexingRawMode()) L->Diag(CurPtr, diag::backslash_newline_space); return true; } #ifdef __SSE2__ #include #elif __ALTIVEC__ #include #undef bool #endif /// We have just read from input the / and * characters that started a comment. /// Read until we find the * and / characters that terminate the comment. /// Note that we don't bother decoding trigraphs or escaped newlines in block /// comments, because they cannot cause the comment to end. The only thing /// that can happen is the comment could end with an escaped newline between /// the terminating * and /. /// /// If we're in KeepCommentMode or any CommentHandler has inserted /// some tokens, this will store the first token and return true. bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr, bool &TokAtPhysicalStartOfLine) { // Scan one character past where we should, looking for a '/' character. Once // we find it, check to see if it was preceded by a *. This common // optimization helps people who like to put a lot of * characters in their // comments. // The first character we get with newlines and trigraphs skipped to handle // the degenerate /*/ case below correctly if the * has an escaped newline // after it. unsigned CharSize; unsigned char C = getCharAndSize(CurPtr, CharSize); CurPtr += CharSize; if (C == 0 && CurPtr == BufferEnd+1) { if (!isLexingRawMode()) Diag(BufferPtr, diag::err_unterminated_block_comment); --CurPtr; // KeepWhitespaceMode should return this broken comment as a token. Since // it isn't a well formed comment, just return it as an 'unknown' token. if (isKeepWhitespaceMode()) { FormTokenWithChars(Result, CurPtr, tok::unknown); return true; } BufferPtr = CurPtr; return false; } // Check to see if the first character after the '/*' is another /. If so, // then this slash does not end the block comment, it is part of it. if (C == '/') C = *CurPtr++; while (true) { // Skip over all non-interesting characters until we find end of buffer or a // (probably ending) '/' character. if (CurPtr + 24 < BufferEnd && // If there is a code-completion point avoid the fast scan because it // doesn't check for '\0'. !(PP && PP->getCodeCompletionFileLoc() == FileLoc)) { // While not aligned to a 16-byte boundary. while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0) C = *CurPtr++; if (C == '/') goto FoundSlash; #ifdef __SSE2__ __m128i Slashes = _mm_set1_epi8('/'); while (CurPtr+16 <= BufferEnd) { int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(const __m128i*)CurPtr, Slashes)); if (cmp != 0) { // Adjust the pointer to point directly after the first slash. It's // not necessary to set C here, it will be overwritten at the end of // the outer loop. CurPtr += llvm::countTrailingZeros(cmp) + 1; goto FoundSlash; } CurPtr += 16; } #elif __ALTIVEC__ __vector unsigned char Slashes = { '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/' }; while (CurPtr+16 <= BufferEnd && !vec_any_eq(*(const vector unsigned char*)CurPtr, Slashes)) CurPtr += 16; #else // Scan for '/' quickly. Many block comments are very large. while (CurPtr[0] != '/' && CurPtr[1] != '/' && CurPtr[2] != '/' && CurPtr[3] != '/' && CurPtr+4 < BufferEnd) { CurPtr += 4; } #endif // It has to be one of the bytes scanned, increment to it and read one. C = *CurPtr++; } // Loop to scan the remainder. while (C != '/' && C != '\0') C = *CurPtr++; if (C == '/') { FoundSlash: if (CurPtr[-2] == '*') // We found the final */. We're done! break; if ((CurPtr[-2] == '\n' || CurPtr[-2] == '\r')) { if (isEndOfBlockCommentWithEscapedNewLine(CurPtr-2, this)) { // We found the final */, though it had an escaped newline between the // * and /. We're done! break; } } if (CurPtr[0] == '*' && CurPtr[1] != '/') { // If this is a /* inside of the comment, emit a warning. Don't do this // if this is a /*/, which will end the comment. This misses cases with // embedded escaped newlines, but oh well. if (!isLexingRawMode()) Diag(CurPtr-1, diag::warn_nested_block_comment); } } else if (C == 0 && CurPtr == BufferEnd+1) { if (!isLexingRawMode()) Diag(BufferPtr, diag::err_unterminated_block_comment); // Note: the user probably forgot a */. We could continue immediately // after the /*, but this would involve lexing a lot of what really is the // comment, which surely would confuse the parser. --CurPtr; // KeepWhitespaceMode should return this broken comment as a token. Since // it isn't a well formed comment, just return it as an 'unknown' token. if (isKeepWhitespaceMode()) { FormTokenWithChars(Result, CurPtr, tok::unknown); return true; } BufferPtr = CurPtr; return false; } else if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) { PP->CodeCompleteNaturalLanguage(); cutOffLexing(); return false; } C = *CurPtr++; } // Notify comment handlers about the comment unless we're in a #if 0 block. if (PP && !isLexingRawMode() && PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr), getSourceLocation(CurPtr)))) { BufferPtr = CurPtr; return true; // A token has to be returned. } // If we are returning comments as tokens, return this comment as a token. if (inKeepCommentMode()) { FormTokenWithChars(Result, CurPtr, tok::comment); return true; } // It is common for the tokens immediately after a /**/ comment to be // whitespace. Instead of going through the big switch, handle it // efficiently now. This is safe even in KeepWhitespaceMode because we would // have already returned above with the comment as a token. if (isHorizontalWhitespace(*CurPtr)) { SkipWhitespace(Result, CurPtr+1, TokAtPhysicalStartOfLine); return false; } // Otherwise, just return so that the next character will be lexed as a token. BufferPtr = CurPtr; Result.setFlag(Token::LeadingSpace); return false; } //===----------------------------------------------------------------------===// // Primary Lexing Entry Points //===----------------------------------------------------------------------===// /// ReadToEndOfLine - Read the rest of the current preprocessor line as an /// uninterpreted string. This switches the lexer out of directive mode. void Lexer::ReadToEndOfLine(SmallVectorImpl *Result) { assert(ParsingPreprocessorDirective && ParsingFilename == false && "Must be in a preprocessing directive!"); Token Tmp; // CurPtr - Cache BufferPtr in an automatic variable. const char *CurPtr = BufferPtr; while (true) { char Char = getAndAdvanceChar(CurPtr, Tmp); switch (Char) { default: if (Result) Result->push_back(Char); break; case 0: // Null. // Found end of file? if (CurPtr-1 != BufferEnd) { if (isCodeCompletionPoint(CurPtr-1)) { PP->CodeCompleteNaturalLanguage(); cutOffLexing(); return; } // Nope, normal character, continue. if (Result) Result->push_back(Char); break; } // FALL THROUGH. case '\r': case '\n': // Okay, we found the end of the line. First, back up past the \0, \r, \n. assert(CurPtr[-1] == Char && "Trigraphs for newline?"); BufferPtr = CurPtr-1; // Next, lex the character, which should handle the EOD transition. Lex(Tmp); if (Tmp.is(tok::code_completion)) { if (PP) PP->CodeCompleteNaturalLanguage(); Lex(Tmp); } assert(Tmp.is(tok::eod) && "Unexpected token!"); // Finally, we're done; return; } } } /// LexEndOfFile - CurPtr points to the end of this file. Handle this /// condition, reporting diagnostics and handling other edge cases as required. /// This returns true if Result contains a token, false if PP.Lex should be /// called again. bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // If we hit the end of the file while parsing a preprocessor directive, // end the preprocessor directive first. The next token returned will // then be the end of file. if (ParsingPreprocessorDirective) { // Done parsing the "line". ParsingPreprocessorDirective = false; // Update the location of token as well as BufferPtr. FormTokenWithChars(Result, CurPtr, tok::eod); // Restore comment saving mode, in case it was disabled for directive. if (PP) resetExtendedTokenMode(); return true; // Have a token. } // If we are in raw mode, return this event as an EOF token. Let the caller // that put us in raw mode handle the event. if (isLexingRawMode()) { Result.startToken(); BufferPtr = BufferEnd; FormTokenWithChars(Result, BufferEnd, tok::eof); return true; } // Issue diagnostics for unterminated #if and missing newline. // If we are in a #if directive, emit an error. while (!ConditionalStack.empty()) { if (PP->getCodeCompletionFileLoc() != FileLoc) PP->Diag(ConditionalStack.back().IfLoc, diag::err_pp_unterminated_conditional); ConditionalStack.pop_back(); } // C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue // a pedwarn. if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) { DiagnosticsEngine &Diags = PP->getDiagnostics(); SourceLocation EndLoc = getSourceLocation(BufferEnd); unsigned DiagID; if (LangOpts.CPlusPlus11) { // C++11 [lex.phases] 2.2 p2 // Prefer the C++98 pedantic compatibility warning over the generic, // non-extension, user-requested "missing newline at EOF" warning. if (!Diags.isIgnored(diag::warn_cxx98_compat_no_newline_eof, EndLoc)) { DiagID = diag::warn_cxx98_compat_no_newline_eof; } else { DiagID = diag::warn_no_newline_eof; } } else { DiagID = diag::ext_no_newline_eof; } Diag(BufferEnd, DiagID) << FixItHint::CreateInsertion(EndLoc, "\n"); } BufferPtr = CurPtr; // Finally, let the preprocessor handle this. return PP->HandleEndOfFile(Result, isPragmaLexer()); } /// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from /// the specified lexer will return a tok::l_paren token, 0 if it is something /// else and 2 if there are no more tokens in the buffer controlled by the /// lexer. unsigned Lexer::isNextPPTokenLParen() { assert(!LexingRawMode && "How can we expand a macro from a skipping buffer?"); // Switch to 'skipping' mode. This will ensure that we can lex a token // without emitting diagnostics, disables macro expansion, and will cause EOF // to return an EOF token instead of popping the include stack. LexingRawMode = true; // Save state that can be changed while lexing so that we can restore it. const char *TmpBufferPtr = BufferPtr; bool inPPDirectiveMode = ParsingPreprocessorDirective; bool atStartOfLine = IsAtStartOfLine; bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine; bool leadingSpace = HasLeadingSpace; Token Tok; Lex(Tok); // Restore state that may have changed. BufferPtr = TmpBufferPtr; ParsingPreprocessorDirective = inPPDirectiveMode; HasLeadingSpace = leadingSpace; IsAtStartOfLine = atStartOfLine; IsAtPhysicalStartOfLine = atPhysicalStartOfLine; // Restore the lexer back to non-skipping mode. LexingRawMode = false; if (Tok.is(tok::eof)) return 2; return Tok.is(tok::l_paren); } /// \brief Find the end of a version control conflict marker. static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd, ConflictMarkerKind CMK) { const char *Terminator = CMK == CMK_Perforce ? "<<<<\n" : ">>>>>>>"; size_t TermLen = CMK == CMK_Perforce ? 5 : 7; auto RestOfBuffer = StringRef(CurPtr, BufferEnd - CurPtr).substr(TermLen); size_t Pos = RestOfBuffer.find(Terminator); while (Pos != StringRef::npos) { // Must occur at start of line. if (Pos == 0 || (RestOfBuffer[Pos - 1] != '\r' && RestOfBuffer[Pos - 1] != '\n')) { RestOfBuffer = RestOfBuffer.substr(Pos+TermLen); Pos = RestOfBuffer.find(Terminator); continue; } return RestOfBuffer.data()+Pos; } return nullptr; } /// IsStartOfConflictMarker - If the specified pointer is the start of a version /// control conflict marker like '<<<<<<<', recognize it as such, emit an error /// and recover nicely. This returns true if it is a conflict marker and false /// if not. bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { // Only a conflict marker if it starts at the beginning of a line. if (CurPtr != BufferStart && CurPtr[-1] != '\n' && CurPtr[-1] != '\r') return false; // Check to see if we have <<<<<<< or >>>>. if (!StringRef(CurPtr, BufferEnd - CurPtr).startswith("<<<<<<<") && !StringRef(CurPtr, BufferEnd - CurPtr).startswith(">>>> ")) return false; // If we have a situation where we don't care about conflict markers, ignore // it. if (CurrentConflictMarkerState || isLexingRawMode()) return false; ConflictMarkerKind Kind = *CurPtr == '<' ? CMK_Normal : CMK_Perforce; // Check to see if there is an ending marker somewhere in the buffer at the // start of a line to terminate this conflict marker. if (FindConflictEnd(CurPtr, BufferEnd, Kind)) { // We found a match. We are really in a conflict marker. // Diagnose this, and ignore to the end of line. Diag(CurPtr, diag::err_conflict_marker); CurrentConflictMarkerState = Kind; // Skip ahead to the end of line. We know this exists because the // end-of-conflict marker starts with \r or \n. while (*CurPtr != '\r' && *CurPtr != '\n') { assert(CurPtr != BufferEnd && "Didn't find end of line"); ++CurPtr; } BufferPtr = CurPtr; return true; } // No end of conflict marker found. return false; } /// HandleEndOfConflictMarker - If this is a '====' or '||||' or '>>>>', or if /// it is '<<<<' and the conflict marker started with a '>>>>' marker, then it /// is the end of a conflict marker. Handle it by ignoring up until the end of /// the line. This returns true if it is a conflict marker and false if not. bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) { // Only a conflict marker if it starts at the beginning of a line. if (CurPtr != BufferStart && CurPtr[-1] != '\n' && CurPtr[-1] != '\r') return false; // If we have a situation where we don't care about conflict markers, ignore // it. if (!CurrentConflictMarkerState || isLexingRawMode()) return false; // Check to see if we have the marker (4 characters in a row). for (unsigned i = 1; i != 4; ++i) if (CurPtr[i] != CurPtr[0]) return false; // If we do have it, search for the end of the conflict marker. This could // fail if it got skipped with a '#if 0' or something. Note that CurPtr might // be the end of conflict marker. if (const char *End = FindConflictEnd(CurPtr, BufferEnd, CurrentConflictMarkerState)) { CurPtr = End; // Skip ahead to the end of line. while (CurPtr != BufferEnd && *CurPtr != '\r' && *CurPtr != '\n') ++CurPtr; BufferPtr = CurPtr; // No longer in the conflict marker. CurrentConflictMarkerState = CMK_None; return true; } return false; } static const char *findPlaceholderEnd(const char *CurPtr, const char *BufferEnd) { if (CurPtr == BufferEnd) return nullptr; BufferEnd -= 1; // Scan until the second last character. for (; CurPtr != BufferEnd; ++CurPtr) { if (CurPtr[0] == '#' && CurPtr[1] == '>') return CurPtr + 2; } return nullptr; } bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) { assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!"); if (!PP || LexingRawMode) return false; const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd); if (!End) return false; const char *Start = CurPtr - 1; if (!LangOpts.AllowEditorPlaceholders) Diag(Start, diag::err_placeholder_in_source); Result.startToken(); FormTokenWithChars(Result, End, tok::raw_identifier); Result.setRawIdentifierData(Start); PP->LookUpIdentifierInfo(Result); Result.setFlag(Token::IsEditorPlaceholder); BufferPtr = End; return true; } bool Lexer::isCodeCompletionPoint(const char *CurPtr) const { if (PP && PP->isCodeCompletionEnabled()) { SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart); return Loc == PP->getCodeCompletionLoc(); } return false; } uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, Token *Result) { unsigned CharSize; char Kind = getCharAndSize(StartPtr, CharSize); unsigned NumHexDigits; if (Kind == 'u') NumHexDigits = 4; else if (Kind == 'U') NumHexDigits = 8; else return 0; if (!LangOpts.CPlusPlus && !LangOpts.C99) { if (Result && !isLexingRawMode()) Diag(SlashLoc, diag::warn_ucn_not_valid_in_c89); return 0; } const char *CurPtr = StartPtr + CharSize; const char *KindLoc = &CurPtr[-1]; uint32_t CodePoint = 0; for (unsigned i = 0; i < NumHexDigits; ++i) { char C = getCharAndSize(CurPtr, CharSize); unsigned Value = llvm::hexDigitValue(C); if (Value == -1U) { if (Result && !isLexingRawMode()) { if (i == 0) { Diag(BufferPtr, diag::warn_ucn_escape_no_digits) << StringRef(KindLoc, 1); } else { Diag(BufferPtr, diag::warn_ucn_escape_incomplete); // If the user wrote \U1234, suggest a fixit to \u. if (i == 4 && NumHexDigits == 8) { CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1); Diag(KindLoc, diag::note_ucn_four_not_eight) << FixItHint::CreateReplacement(URange, "u"); } } } return 0; } CodePoint <<= 4; CodePoint += Value; CurPtr += CharSize; } if (Result) { Result->setFlag(Token::HasUCN); if (CurPtr - StartPtr == (ptrdiff_t)NumHexDigits + 2) StartPtr = CurPtr; else while (StartPtr != CurPtr) (void)getAndAdvanceChar(StartPtr, *Result); } else { StartPtr = CurPtr; } // Don't apply C family restrictions to UCNs in assembly mode if (LangOpts.AsmPreprocessor) return CodePoint; // C99 6.4.3p2: A universal character name shall not specify a character whose // short identifier is less than 00A0 other than 0024 ($), 0040 (@), or // 0060 (`), nor one in the range D800 through DFFF inclusive.) // C++11 [lex.charset]p2: If the hexadecimal value for a // universal-character-name corresponds to a surrogate code point (in the // range 0xD800-0xDFFF, inclusive), the program is ill-formed. Additionally, // if the hexadecimal value for a universal-character-name outside the // c-char-sequence, s-char-sequence, or r-char-sequence of a character or // string literal corresponds to a control character (in either of the // ranges 0x00-0x1F or 0x7F-0x9F, both inclusive) or to a character in the // basic source character set, the program is ill-formed. if (CodePoint < 0xA0) { if (CodePoint == 0x24 || CodePoint == 0x40 || CodePoint == 0x60) return CodePoint; // We don't use isLexingRawMode() here because we need to warn about bad // UCNs even when skipping preprocessing tokens in a #if block. if (Result && PP) { if (CodePoint < 0x20 || CodePoint >= 0x7F) Diag(BufferPtr, diag::err_ucn_control_character); else { char C = static_cast(CodePoint); Diag(BufferPtr, diag::err_ucn_escape_basic_scs) << StringRef(&C, 1); } } return 0; } else if (CodePoint >= 0xD800 && CodePoint <= 0xDFFF) { // C++03 allows UCNs representing surrogate characters. C99 and C++11 don't. // We don't use isLexingRawMode() here because we need to diagnose bad // UCNs even when skipping preprocessing tokens in a #if block. if (Result && PP) { if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus11) Diag(BufferPtr, diag::warn_ucn_escape_surrogate); else Diag(BufferPtr, diag::err_ucn_escape_invalid); } return 0; } return CodePoint; } bool Lexer::CheckUnicodeWhitespace(Token &Result, uint32_t C, const char *CurPtr) { static const llvm::sys::UnicodeCharSet UnicodeWhitespaceChars( UnicodeWhitespaceCharRanges); if (!isLexingRawMode() && !PP->isPreprocessedOutput() && UnicodeWhitespaceChars.contains(C)) { Diag(BufferPtr, diag::ext_unicode_whitespace) << makeCharRange(*this, BufferPtr, CurPtr); Result.setFlag(Token::LeadingSpace); return true; } return false; } bool Lexer::LexUnicode(Token &Result, uint32_t C, const char *CurPtr) { if (isAllowedIDChar(C, LangOpts) && isAllowedInitiallyIDChar(C, LangOpts)) { if (!isLexingRawMode() && !ParsingPreprocessorDirective && !PP->isPreprocessedOutput()) { maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C, makeCharRange(*this, BufferPtr, CurPtr), /*IsFirst=*/true); } MIOpt.ReadToken(); return LexIdentifier(Result, CurPtr); } if (!isLexingRawMode() && !ParsingPreprocessorDirective && !PP->isPreprocessedOutput() && !isASCII(*BufferPtr) && !isAllowedIDChar(C, LangOpts)) { // Non-ASCII characters tend to creep into source code unintentionally. // Instead of letting the parser complain about the unknown token, // just drop the character. // Note that we can /only/ do this when the non-ASCII character is actually // spelled as Unicode, not written as a UCN. The standard requires that // we not throw away any possible preprocessor tokens, but there's a // loophole in the mapping of Unicode characters to basic character set // characters that allows us to map these particular characters to, say, // whitespace. Diag(BufferPtr, diag::err_non_ascii) << FixItHint::CreateRemoval(makeCharRange(*this, BufferPtr, CurPtr)); BufferPtr = CurPtr; return false; } // Otherwise, we have an explicit UCN or a character that's unlikely to show // up by accident. MIOpt.ReadToken(); FormTokenWithChars(Result, CurPtr, tok::unknown); return true; } void Lexer::PropagateLineStartLeadingSpaceInfo(Token &Result) { IsAtStartOfLine = Result.isAtStartOfLine(); HasLeadingSpace = Result.hasLeadingSpace(); HasLeadingEmptyMacro = Result.hasLeadingEmptyMacro(); // Note that this doesn't affect IsAtPhysicalStartOfLine. } bool Lexer::Lex(Token &Result) { // Start a new token. Result.startToken(); // Set up misc whitespace flags for LexTokenInternal. if (IsAtStartOfLine) { Result.setFlag(Token::StartOfLine); IsAtStartOfLine = false; } if (HasLeadingSpace) { Result.setFlag(Token::LeadingSpace); HasLeadingSpace = false; } if (HasLeadingEmptyMacro) { Result.setFlag(Token::LeadingEmptyMacro); HasLeadingEmptyMacro = false; } bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine; IsAtPhysicalStartOfLine = false; bool isRawLex = isLexingRawMode(); (void) isRawLex; bool returnedToken = LexTokenInternal(Result, atPhysicalStartOfLine); // (After the LexTokenInternal call, the lexer might be destroyed.) assert((returnedToken || !isRawLex) && "Raw lex must succeed"); return returnedToken; } /// LexTokenInternal - This implements a simple C family lexer. It is an /// extremely performance critical piece of code. This assumes that the buffer /// has a null character at the end of the file. This returns a preprocessing /// token, not a normal token, as such, it is an internal interface. It assumes /// that the Flags of result have been cleared before calling this. bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) { LexNextToken: // New token, can't need cleaning yet. Result.clearFlag(Token::NeedsCleaning); Result.setIdentifierInfo(nullptr); // CurPtr - Cache BufferPtr in an automatic variable. const char *CurPtr = BufferPtr; // Small amounts of horizontal whitespace is very common between tokens. if ((*CurPtr == ' ') || (*CurPtr == '\t')) { ++CurPtr; while ((*CurPtr == ' ') || (*CurPtr == '\t')) ++CurPtr; // If we are keeping whitespace and other tokens, just return what we just // skipped. The next lexer invocation will return the token after the // whitespace. if (isKeepWhitespaceMode()) { FormTokenWithChars(Result, CurPtr, tok::unknown); // FIXME: The next token will not have LeadingSpace set. return true; } BufferPtr = CurPtr; Result.setFlag(Token::LeadingSpace); } unsigned SizeTmp, SizeTmp2; // Temporaries for use in cases below. // Read a character, advancing over it. char Char = getAndAdvanceChar(CurPtr, Result); tok::TokenKind Kind; switch (Char) { case 0: // Null. // Found end of file? if (CurPtr-1 == BufferEnd) return LexEndOfFile(Result, CurPtr-1); // Check if we are performing code completion. if (isCodeCompletionPoint(CurPtr-1)) { // Return the code-completion token. Result.startToken(); FormTokenWithChars(Result, CurPtr, tok::code_completion); return true; } if (!isLexingRawMode()) Diag(CurPtr-1, diag::null_in_file); Result.setFlag(Token::LeadingSpace); if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine)) return true; // KeepWhitespaceMode // We know the lexer hasn't changed, so just try again with this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; case 26: // DOS & CP/M EOF: "^Z". // If we're in Microsoft extensions mode, treat this as end of file. if (LangOpts.MicrosoftExt) { if (!isLexingRawMode()) Diag(CurPtr-1, diag::ext_ctrl_z_eof_microsoft); return LexEndOfFile(Result, CurPtr-1); } // If Microsoft extensions are disabled, this is just random garbage. Kind = tok::unknown; break; case '\n': case '\r': // If we are inside a preprocessor directive and we see the end of line, // we know we are done with the directive, so return an EOD token. if (ParsingPreprocessorDirective) { // Done parsing the "line". ParsingPreprocessorDirective = false; // Restore comment saving mode, in case it was disabled for directive. if (PP) resetExtendedTokenMode(); // Since we consumed a newline, we are back at the start of a line. IsAtStartOfLine = true; IsAtPhysicalStartOfLine = true; Kind = tok::eod; break; } // No leading whitespace seen so far. Result.clearFlag(Token::LeadingSpace); if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine)) return true; // KeepWhitespaceMode // We only saw whitespace, so just try again with this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; case ' ': case '\t': case '\f': case '\v': SkipHorizontalWhitespace: Result.setFlag(Token::LeadingSpace); if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine)) return true; // KeepWhitespaceMode SkipIgnoredUnits: CurPtr = BufferPtr; // If the next token is obviously a // or /* */ comment, skip it efficiently // too (without going through the big switch stmt). if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() && LangOpts.LineComment && (LangOpts.CPlusPlus || !LangOpts.TraditionalCPP)) { if (SkipLineComment(Result, CurPtr+2, TokAtPhysicalStartOfLine)) return true; // There is a token to return. goto SkipIgnoredUnits; } else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) { if (SkipBlockComment(Result, CurPtr+2, TokAtPhysicalStartOfLine)) return true; // There is a token to return. goto SkipIgnoredUnits; } else if (isHorizontalWhitespace(*CurPtr)) { goto SkipHorizontalWhitespace; } // We only saw whitespace, so just try again with this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; // C99 6.4.4.1: Integer Constants. // C99 6.4.4.2: Floating Constants. case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); return LexNumericConstant(Result, CurPtr); case 'u': // Identifier (uber) or C11/C++11 UTF-8 or UTF-16 string literal // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); if (LangOpts.CPlusPlus11 || LangOpts.C11) { Char = getCharAndSize(CurPtr, SizeTmp); // UTF-16 string literal if (Char == '"') return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), tok::utf16_string_literal); // UTF-16 character constant if (Char == '\'') return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result), tok::utf16_char_constant); // UTF-16 raw string literal if (Char == 'R' && LangOpts.CPlusPlus11 && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"') return LexRawStringLiteral(Result, ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result), tok::utf16_string_literal); if (Char == '8') { char Char2 = getCharAndSize(CurPtr + SizeTmp, SizeTmp2); // UTF-8 string literal if (Char2 == '"') return LexStringLiteral(Result, ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result), tok::utf8_string_literal); if (Char2 == '\'' && LangOpts.CPlusPlus1z) return LexCharConstant( Result, ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result), tok::utf8_char_constant); if (Char2 == 'R' && LangOpts.CPlusPlus11) { unsigned SizeTmp3; char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3); // UTF-8 raw string literal if (Char3 == '"') { return LexRawStringLiteral(Result, ConsumeChar(ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result), SizeTmp3, Result), tok::utf8_string_literal); } } } } // treat u like the start of an identifier. return LexIdentifier(Result, CurPtr); case 'U': // Identifier (Uber) or C11/C++11 UTF-32 string literal // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); if (LangOpts.CPlusPlus11 || LangOpts.C11) { Char = getCharAndSize(CurPtr, SizeTmp); // UTF-32 string literal if (Char == '"') return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), tok::utf32_string_literal); // UTF-32 character constant if (Char == '\'') return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result), tok::utf32_char_constant); // UTF-32 raw string literal if (Char == 'R' && LangOpts.CPlusPlus11 && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"') return LexRawStringLiteral(Result, ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result), tok::utf32_string_literal); } // treat U like the start of an identifier. return LexIdentifier(Result, CurPtr); case 'R': // Identifier or C++0x raw string literal // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); if (LangOpts.CPlusPlus11) { Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '"') return LexRawStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), tok::string_literal); } // treat R like the start of an identifier. return LexIdentifier(Result, CurPtr); case 'L': // Identifier (Loony) or wide literal (L'x' or L"xyz"). // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); Char = getCharAndSize(CurPtr, SizeTmp); // Wide string literal. if (Char == '"') return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), tok::wide_string_literal); // Wide raw string literal. if (LangOpts.CPlusPlus11 && Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"') return LexRawStringLiteral(Result, ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result), tok::wide_string_literal); // Wide character constant. if (Char == '\'') return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result), tok::wide_char_constant); // FALL THROUGH, treating L like the start of an identifier. // C99 6.4.2: Identifiers. case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': /*'L'*/case 'M': case 'N': case 'O': case 'P': case 'Q': /*'R'*/case 'S': case 'T': /*'U'*/ case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': /*'u'*/ case 'v': case 'w': case 'x': case 'y': case 'z': case '_': // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); return LexIdentifier(Result, CurPtr); case '$': // $ in identifiers. if (LangOpts.DollarIdents) { if (!isLexingRawMode()) Diag(CurPtr-1, diag::ext_dollar_in_identifier); // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); return LexIdentifier(Result, CurPtr); } Kind = tok::unknown; break; // C99 6.4.4: Character Constants. case '\'': // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); return LexCharConstant(Result, CurPtr, tok::char_constant); // C99 6.4.5: String Literals. case '"': // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); return LexStringLiteral(Result, CurPtr, tok::string_literal); // C99 6.4.6: Punctuators. case '?': Kind = tok::question; break; case '[': Kind = tok::l_square; break; case ']': Kind = tok::r_square; break; case '(': Kind = tok::l_paren; break; case ')': Kind = tok::r_paren; break; case '{': Kind = tok::l_brace; break; case '}': Kind = tok::r_brace; break; case '.': Char = getCharAndSize(CurPtr, SizeTmp); if (Char >= '0' && Char <= '9') { // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result)); } else if (LangOpts.CPlusPlus && Char == '*') { Kind = tok::periodstar; CurPtr += SizeTmp; } else if (Char == '.' && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '.') { Kind = tok::ellipsis; CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); } else { Kind = tok::period; } break; case '&': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '&') { Kind = tok::ampamp; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else if (Char == '=') { Kind = tok::ampequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { Kind = tok::amp; } break; case '*': if (getCharAndSize(CurPtr, SizeTmp) == '=') { Kind = tok::starequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { Kind = tok::star; } break; case '+': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '+') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::plusplus; } else if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::plusequal; } else { Kind = tok::plus; } break; case '-': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '-') { // -- CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::minusminus; } else if (Char == '>' && LangOpts.CPlusPlus && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') { // C++ ->* CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); Kind = tok::arrowstar; } else if (Char == '>') { // -> CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::arrow; } else if (Char == '=') { // -= CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::minusequal; } else { Kind = tok::minus; } break; case '~': Kind = tok::tilde; break; case '!': if (getCharAndSize(CurPtr, SizeTmp) == '=') { Kind = tok::exclaimequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { Kind = tok::exclaim; } break; case '/': // 6.4.9: Comments Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '/') { // Line comment. // Even if Line comments are disabled (e.g. in C89 mode), we generally // want to lex this as a comment. There is one problem with this though, // that in one particular corner case, this can change the behavior of the // resultant program. For example, In "foo //**/ bar", C89 would lex // this as "foo / bar" and langauges with Line comments would lex it as // "foo". Check to see if the character after the second slash is a '*'. // If so, we will lex that as a "/" instead of the start of a comment. // However, we never do this if we are just preprocessing. bool TreatAsComment = LangOpts.LineComment && (LangOpts.CPlusPlus || !LangOpts.TraditionalCPP); if (!TreatAsComment) if (!(PP && PP->isPreprocessedOutput())) TreatAsComment = getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*'; if (TreatAsComment) { if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result), TokAtPhysicalStartOfLine)) return true; // There is a token to return. // It is common for the tokens immediately after a // comment to be // whitespace (indentation for the next line). Instead of going through // the big switch, handle it efficiently now. goto SkipIgnoredUnits; } } if (Char == '*') { // /**/ comment. if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result), TokAtPhysicalStartOfLine)) return true; // There is a token to return. // We only saw whitespace, so just try again with this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; } if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::slashequal; } else { Kind = tok::slash; } break; case '%': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '=') { Kind = tok::percentequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else if (LangOpts.Digraphs && Char == '>') { Kind = tok::r_brace; // '%>' -> '}' CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else if (LangOpts.Digraphs && Char == ':') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '%' && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == ':') { Kind = tok::hashhash; // '%:%:' -> '##' CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); } else if (Char == '@' && LangOpts.MicrosoftExt) {// %:@ -> #@ -> Charize CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); if (!isLexingRawMode()) Diag(BufferPtr, diag::ext_charize_microsoft); Kind = tok::hashat; } else { // '%:' -> '#' // We parsed a # character. If this occurs at the start of the line, // it's actually the start of a preprocessing directive. Callback to // the preprocessor to handle it. // TODO: -fpreprocessed mode?? if (TokAtPhysicalStartOfLine && !LexingRawMode && !Is_PragmaLexer) goto HandleDirective; Kind = tok::hash; } } else { Kind = tok::percent; } break; case '<': Char = getCharAndSize(CurPtr, SizeTmp); if (ParsingFilename) { return LexAngledStringLiteral(Result, CurPtr); } else if (Char == '<') { char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2); if (After == '=') { Kind = tok::lesslessequal; CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); } else if (After == '<' && IsStartOfConflictMarker(CurPtr-1)) { // If this is actually a '<<<<<<<' version control conflict marker, // recognize it as such and recover nicely. goto LexNextToken; } else if (After == '<' && HandleEndOfConflictMarker(CurPtr-1)) { // If this is '<<<<' and we're in a Perforce-style conflict marker, // ignore it. goto LexNextToken; } else if (LangOpts.CUDA && After == '<') { Kind = tok::lesslessless; CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); } else { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::lessless; } } else if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::lessequal; } else if (LangOpts.Digraphs && Char == ':') { // '<:' -> '[' if (LangOpts.CPlusPlus11 && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == ':') { // C++0x [lex.pptoken]p3: // Otherwise, if the next three characters are <:: and the subsequent // character is neither : nor >, the < is treated as a preprocessor // token by itself and not as the first character of the alternative // token <:. unsigned SizeTmp3; char After = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3); if (After != ':' && After != '>') { Kind = tok::less; if (!isLexingRawMode()) Diag(BufferPtr, diag::warn_cxx98_compat_less_colon_colon); break; } } CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::l_square; } else if (LangOpts.Digraphs && Char == '%') { // '<%' -> '{' CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::l_brace; } else if (Char == '#' && lexEditorPlaceholder(Result, CurPtr)) { return true; } else { Kind = tok::less; } break; case '>': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::greaterequal; } else if (Char == '>') { char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2); if (After == '=') { CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); Kind = tok::greatergreaterequal; } else if (After == '>' && IsStartOfConflictMarker(CurPtr-1)) { // If this is actually a '>>>>' conflict marker, recognize it as such // and recover nicely. goto LexNextToken; } else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) { // If this is '>>>>>>>' and we're in a conflict marker, ignore it. goto LexNextToken; } else if (LangOpts.CUDA && After == '>') { Kind = tok::greatergreatergreater; CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); } else { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::greatergreater; } } else { Kind = tok::greater; } break; case '^': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::caretequal; } else if (LangOpts.OpenCL && Char == '^') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::caretcaret; } else { Kind = tok::caret; } break; case '|': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '=') { Kind = tok::pipeequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else if (Char == '|') { // If this is '|||||||' and we're in a conflict marker, ignore it. if (CurPtr[1] == '|' && HandleEndOfConflictMarker(CurPtr-1)) goto LexNextToken; Kind = tok::pipepipe; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { Kind = tok::pipe; } break; case ':': Char = getCharAndSize(CurPtr, SizeTmp); if (LangOpts.Digraphs && Char == '>') { Kind = tok::r_square; // ':>' -> ']' CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else if (LangOpts.CPlusPlus && Char == ':') { Kind = tok::coloncolon; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { Kind = tok::colon; } break; case ';': Kind = tok::semi; break; case '=': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '=') { // If this is '====' and we're in a conflict marker, ignore it. if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1)) goto LexNextToken; Kind = tok::equalequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { Kind = tok::equal; } break; case ',': Kind = tok::comma; break; case '#': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '#') { Kind = tok::hashhash; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else if (Char == '@' && LangOpts.MicrosoftExt) { // #@ -> Charize Kind = tok::hashat; if (!isLexingRawMode()) Diag(BufferPtr, diag::ext_charize_microsoft); CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { // We parsed a # character. If this occurs at the start of the line, // it's actually the start of a preprocessing directive. Callback to // the preprocessor to handle it. // TODO: -fpreprocessed mode?? if (TokAtPhysicalStartOfLine && !LexingRawMode && !Is_PragmaLexer) goto HandleDirective; Kind = tok::hash; } break; case '@': // Objective C support. if (CurPtr[-1] == '@' && LangOpts.ObjC1) Kind = tok::at; else Kind = tok::unknown; break; // UCNs (C99 6.4.3, C++11 [lex.charset]p2) case '\\': if (!LangOpts.AsmPreprocessor) { if (uint32_t CodePoint = tryReadUCN(CurPtr, BufferPtr, &Result)) { if (CheckUnicodeWhitespace(Result, CodePoint, CurPtr)) { if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine)) return true; // KeepWhitespaceMode // We only saw whitespace, so just try again with this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; } return LexUnicode(Result, CodePoint, CurPtr); } } Kind = tok::unknown; break; default: { if (isASCII(Char)) { Kind = tok::unknown; break; } llvm::UTF32 CodePoint; // We can't just reset CurPtr to BufferPtr because BufferPtr may point to // an escaped newline. --CurPtr; llvm::ConversionResult Status = llvm::convertUTF8Sequence((const llvm::UTF8 **)&CurPtr, (const llvm::UTF8 *)BufferEnd, &CodePoint, llvm::strictConversion); if (Status == llvm::conversionOK) { if (CheckUnicodeWhitespace(Result, CodePoint, CurPtr)) { if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine)) return true; // KeepWhitespaceMode // We only saw whitespace, so just try again with this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; } return LexUnicode(Result, CodePoint, CurPtr); } if (isLexingRawMode() || ParsingPreprocessorDirective || PP->isPreprocessedOutput()) { ++CurPtr; Kind = tok::unknown; break; } // Non-ASCII characters tend to creep into source code unintentionally. // Instead of letting the parser complain about the unknown token, // just diagnose the invalid UTF-8, then drop the character. Diag(CurPtr, diag::err_invalid_utf8); BufferPtr = CurPtr+1; // We're pretending the character didn't exist, so just try again with // this lexer. // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; } } // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); // Update the location of token as well as BufferPtr. FormTokenWithChars(Result, CurPtr, Kind); return true; HandleDirective: // We parsed a # character and it's the start of a preprocessing directive. FormTokenWithChars(Result, CurPtr, tok::hash); PP->HandleDirective(Result); if (PP->hadModuleLoaderFatalFailure()) { // With a fatal failure in the module loader, we abort parsing. assert(Result.is(tok::eof) && "Preprocessor did not set tok:eof"); return true; } // We parsed the directive; lex a token with the new state. return false; } Index: vendor/clang/dist/lib/Sema/Sema.cpp =================================================================== --- vendor/clang/dist/lib/Sema/Sema.cpp (revision 318415) +++ vendor/clang/dist/lib/Sema/Sema.cpp (revision 318416) @@ -1,1692 +1,1691 @@ //===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the actions class which performs semantic analysis and // builds an AST out of a parse stream. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" using namespace clang; using namespace sema; SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) { return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts); } ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context, const Preprocessor &PP) { PrintingPolicy Policy = Context.getPrintingPolicy(); // Our printing policy is copied over the ASTContext printing policy whenever // a diagnostic is emitted, so recompute it. Policy.Bool = Context.getLangOpts().Bool; if (!Policy.Bool) { if (const MacroInfo *BoolMacro = PP.getMacroInfo(Context.getBoolName())) { Policy.Bool = BoolMacro->isObjectLike() && BoolMacro->getNumTokens() == 1 && BoolMacro->getReplacementToken(0).is(tok::kw__Bool); } } return Policy; } void Sema::ActOnTranslationUnitScope(Scope *S) { TUScope = S; PushDeclContext(S, Context.getTranslationUnitDecl()); } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) : ExternalSource(nullptr), isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), CollectStats(false), CodeCompleter(CodeCompleter), CurContext(nullptr), OriginalLexicalContext(nullptr), MSStructPragmaOn(false), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr), IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), NSValueDecl(nullptr), NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false), - TUKind(TUKind), NumSFINAEErrors(0), CachedFakeTopLevelModule(nullptr), - AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), - NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), - CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), - TyposCorrected(0), AnalysisWarnings(*this), + TUKind(TUKind), NumSFINAEErrors(0), AccessCheckingSFINAE(false), + InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), + ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr), + DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr), CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) { TUScope = nullptr; LoadedExternalKnownNamespaces = false; for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I) NSNumberLiteralMethods[I] = nullptr; if (getLangOpts().ObjC1) NSAPIObj.reset(new NSAPI(Context)); if (getLangOpts().CPlusPlus) FieldCollector.reset(new CXXFieldCollector()); // Tell diagnostics how to render things from the AST library. Diags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &Context); ExprEvalContexts.emplace_back( ExpressionEvaluationContext::PotentiallyEvaluated, 0, CleanupInfo{}, nullptr, false); FunctionScopes.push_back(new FunctionScopeInfo(Diags)); // Initilization of data sharing attributes stack for OpenMP InitDataSharingAttributesStack(); } void Sema::addImplicitTypedef(StringRef Name, QualType T) { DeclarationName DN = &Context.Idents.get(Name); if (IdResolver.begin(DN) == IdResolver.end()) PushOnScopeChains(Context.buildImplicitTypedef(T, Name), TUScope); } void Sema::Initialize() { if (SemaConsumer *SC = dyn_cast(&Consumer)) SC->InitializeSema(*this); // Tell the external Sema source about this Sema object. if (ExternalSemaSource *ExternalSema = dyn_cast_or_null(Context.getExternalSource())) ExternalSema->InitializeSema(*this); // This needs to happen after ExternalSemaSource::InitializeSema(this) or we // will not be able to merge any duplicate __va_list_tag decls correctly. VAListTagName = PP.getIdentifierInfo("__va_list_tag"); if (!TUScope) return; // Initialize predefined 128-bit integer types, if needed. if (Context.getTargetInfo().hasInt128Type()) { // If either of the 128-bit integer types are unavailable to name lookup, // define them now. DeclarationName Int128 = &Context.Idents.get("__int128_t"); if (IdResolver.begin(Int128) == IdResolver.end()) PushOnScopeChains(Context.getInt128Decl(), TUScope); DeclarationName UInt128 = &Context.Idents.get("__uint128_t"); if (IdResolver.begin(UInt128) == IdResolver.end()) PushOnScopeChains(Context.getUInt128Decl(), TUScope); } // Initialize predefined Objective-C types: if (getLangOpts().ObjC1) { // If 'SEL' does not yet refer to any declarations, make it refer to the // predefined 'SEL'. DeclarationName SEL = &Context.Idents.get("SEL"); if (IdResolver.begin(SEL) == IdResolver.end()) PushOnScopeChains(Context.getObjCSelDecl(), TUScope); // If 'id' does not yet refer to any declarations, make it refer to the // predefined 'id'. DeclarationName Id = &Context.Idents.get("id"); if (IdResolver.begin(Id) == IdResolver.end()) PushOnScopeChains(Context.getObjCIdDecl(), TUScope); // Create the built-in typedef for 'Class'. DeclarationName Class = &Context.Idents.get("Class"); if (IdResolver.begin(Class) == IdResolver.end()) PushOnScopeChains(Context.getObjCClassDecl(), TUScope); // Create the built-in forward declaratino for 'Protocol'. DeclarationName Protocol = &Context.Idents.get("Protocol"); if (IdResolver.begin(Protocol) == IdResolver.end()) PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope); } // Create the internal type for the *StringMakeConstantString builtins. DeclarationName ConstantString = &Context.Idents.get("__NSConstantString"); if (IdResolver.begin(ConstantString) == IdResolver.end()) PushOnScopeChains(Context.getCFConstantStringDecl(), TUScope); // Initialize Microsoft "predefined C++ types". if (getLangOpts().MSVCCompat) { if (getLangOpts().CPlusPlus && IdResolver.begin(&Context.Idents.get("type_info")) == IdResolver.end()) PushOnScopeChains(Context.buildImplicitRecord("type_info", TTK_Class), TUScope); addImplicitTypedef("size_t", Context.getSizeType()); } // Initialize predefined OpenCL types and supported extensions and (optional) // core features. if (getLangOpts().OpenCL) { getOpenCLOptions().addSupport(Context.getTargetInfo().getSupportedOpenCLOpts()); getOpenCLOptions().enableSupportedCore(getLangOpts().OpenCLVersion); addImplicitTypedef("sampler_t", Context.OCLSamplerTy); addImplicitTypedef("event_t", Context.OCLEventTy); if (getLangOpts().OpenCLVersion >= 200) { addImplicitTypedef("clk_event_t", Context.OCLClkEventTy); addImplicitTypedef("queue_t", Context.OCLQueueTy); addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy); addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy)); addImplicitTypedef("atomic_uint", Context.getAtomicType(Context.UnsignedIntTy)); auto AtomicLongT = Context.getAtomicType(Context.LongTy); addImplicitTypedef("atomic_long", AtomicLongT); auto AtomicULongT = Context.getAtomicType(Context.UnsignedLongTy); addImplicitTypedef("atomic_ulong", AtomicULongT); addImplicitTypedef("atomic_float", Context.getAtomicType(Context.FloatTy)); auto AtomicDoubleT = Context.getAtomicType(Context.DoubleTy); addImplicitTypedef("atomic_double", AtomicDoubleT); // OpenCLC v2.0, s6.13.11.6 requires that atomic_flag is implemented as // 32-bit integer and OpenCLC v2.0, s6.1.1 int is always 32-bit wide. addImplicitTypedef("atomic_flag", Context.getAtomicType(Context.IntTy)); auto AtomicIntPtrT = Context.getAtomicType(Context.getIntPtrType()); addImplicitTypedef("atomic_intptr_t", AtomicIntPtrT); auto AtomicUIntPtrT = Context.getAtomicType(Context.getUIntPtrType()); addImplicitTypedef("atomic_uintptr_t", AtomicUIntPtrT); auto AtomicSizeT = Context.getAtomicType(Context.getSizeType()); addImplicitTypedef("atomic_size_t", AtomicSizeT); auto AtomicPtrDiffT = Context.getAtomicType(Context.getPointerDiffType()); addImplicitTypedef("atomic_ptrdiff_t", AtomicPtrDiffT); // OpenCL v2.0 s6.13.11.6: // - The atomic_long and atomic_ulong types are supported if the // cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics // extensions are supported. // - The atomic_double type is only supported if double precision // is supported and the cl_khr_int64_base_atomics and // cl_khr_int64_extended_atomics extensions are supported. // - If the device address space is 64-bits, the data types // atomic_intptr_t, atomic_uintptr_t, atomic_size_t and // atomic_ptrdiff_t are supported if the cl_khr_int64_base_atomics and // cl_khr_int64_extended_atomics extensions are supported. std::vector Atomic64BitTypes; Atomic64BitTypes.push_back(AtomicLongT); Atomic64BitTypes.push_back(AtomicULongT); Atomic64BitTypes.push_back(AtomicDoubleT); if (Context.getTypeSize(AtomicSizeT) == 64) { Atomic64BitTypes.push_back(AtomicSizeT); Atomic64BitTypes.push_back(AtomicIntPtrT); Atomic64BitTypes.push_back(AtomicUIntPtrT); Atomic64BitTypes.push_back(AtomicPtrDiffT); } for (auto &I : Atomic64BitTypes) setOpenCLExtensionForType(I, "cl_khr_int64_base_atomics cl_khr_int64_extended_atomics"); setOpenCLExtensionForType(AtomicDoubleT, "cl_khr_fp64"); } setOpenCLExtensionForType(Context.DoubleTy, "cl_khr_fp64"); #define GENERIC_IMAGE_TYPE_EXT(Type, Id, Ext) \ setOpenCLExtensionForType(Context.Id, Ext); #include "clang/Basic/OpenCLImageTypes.def" }; if (Context.getTargetInfo().hasBuiltinMSVaList()) { DeclarationName MSVaList = &Context.Idents.get("__builtin_ms_va_list"); if (IdResolver.begin(MSVaList) == IdResolver.end()) PushOnScopeChains(Context.getBuiltinMSVaListDecl(), TUScope); } DeclarationName BuiltinVaList = &Context.Idents.get("__builtin_va_list"); if (IdResolver.begin(BuiltinVaList) == IdResolver.end()) PushOnScopeChains(Context.getBuiltinVaListDecl(), TUScope); } Sema::~Sema() { if (VisContext) FreeVisContext(); // Kill all the active scopes. for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I) delete FunctionScopes[I]; if (FunctionScopes.size() == 1) delete FunctionScopes[0]; // Tell the SemaConsumer to forget about us; we're going out of scope. if (SemaConsumer *SC = dyn_cast(&Consumer)) SC->ForgetSema(); // Detach from the external Sema source. if (ExternalSemaSource *ExternalSema = dyn_cast_or_null(Context.getExternalSource())) ExternalSema->ForgetSema(); // If Sema's ExternalSource is the multiplexer - we own it. if (isMultiplexExternalSource) delete ExternalSource; threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache); // Destroys data sharing attributes stack for OpenMP DestroyDataSharingAttributesStack(); assert(DelayedTypos.empty() && "Uncorrected typos!"); } /// makeUnavailableInSystemHeader - There is an error in the current /// context. If we're still in a system header, and we can plausibly /// make the relevant declaration unavailable instead of erroring, do /// so and return true. bool Sema::makeUnavailableInSystemHeader(SourceLocation loc, UnavailableAttr::ImplicitReason reason) { // If we're not in a function, it's an error. FunctionDecl *fn = dyn_cast(CurContext); if (!fn) return false; // If we're in template instantiation, it's an error. if (inTemplateInstantiation()) return false; // If that function's not in a system header, it's an error. if (!Context.getSourceManager().isInSystemHeader(loc)) return false; // If the function is already unavailable, it's not an error. if (fn->hasAttr()) return true; fn->addAttr(UnavailableAttr::CreateImplicit(Context, "", reason, loc)); return true; } ASTMutationListener *Sema::getASTMutationListener() const { return getASTConsumer().GetASTMutationListener(); } ///\brief Registers an external source. If an external source already exists, /// creates a multiplex external source and appends to it. /// ///\param[in] E - A non-null external sema source. /// void Sema::addExternalSource(ExternalSemaSource *E) { assert(E && "Cannot use with NULL ptr"); if (!ExternalSource) { ExternalSource = E; return; } if (isMultiplexExternalSource) static_cast(ExternalSource)->addSource(*E); else { ExternalSource = new MultiplexExternalSemaSource(*ExternalSource, *E); isMultiplexExternalSource = true; } } /// \brief Print out statistics about the semantic analysis. void Sema::PrintStats() const { llvm::errs() << "\n*** Semantic Analysis Stats:\n"; llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n"; BumpAlloc.PrintStats(); AnalysisWarnings.PrintStats(); } void Sema::diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, SourceLocation Loc) { Optional ExprNullability = SrcType->getNullability(Context); if (!ExprNullability || *ExprNullability != NullabilityKind::Nullable) return; Optional TypeNullability = DstType->getNullability(Context); if (!TypeNullability || *TypeNullability != NullabilityKind::NonNull) return; Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType; } void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer) return; if (E->getType()->isNullPtrType()) return; // nullptr only exists from C++11 on, so don't warn on its absence earlier. if (!getLangOpts().CPlusPlus11) return; Diag(E->getLocStart(), diag::warn_zero_as_null_pointer_constant) << FixItHint::CreateReplacement(E->getSourceRange(), "nullptr"); } /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// The result is of the given category. ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, CastKind Kind, ExprValueKind VK, const CXXCastPath *BasePath, CheckedConversionKind CCK) { #ifndef NDEBUG if (VK == VK_RValue && !E->isRValue()) { switch (Kind) { default: llvm_unreachable("can't implicitly cast lvalue to rvalue with this cast " "kind"); case CK_LValueToRValue: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: case CK_ToVoid: break; } } assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue"); #endif diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getLocStart()); diagnoseZeroToNullptrConversion(Kind, E); QualType ExprTy = Context.getCanonicalType(E->getType()); QualType TypeTy = Context.getCanonicalType(Ty); if (ExprTy == TypeTy) return E; // C++1z [conv.array]: The temporary materialization conversion is applied. // We also use this to fuel C++ DR1213, which applies to C++11 onwards. if (Kind == CK_ArrayToPointerDecay && getLangOpts().CPlusPlus && E->getValueKind() == VK_RValue) { // The temporary is an lvalue in C++98 and an xvalue otherwise. ExprResult Materialized = CreateMaterializeTemporaryExpr( E->getType(), E, !getLangOpts().CPlusPlus11); if (Materialized.isInvalid()) return ExprError(); E = Materialized.get(); } if (ImplicitCastExpr *ImpCast = dyn_cast(E)) { if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) { ImpCast->setType(Ty); ImpCast->setValueKind(VK); return E; } } return ImplicitCastExpr::Create(Context, Ty, Kind, E, BasePath, VK); } /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding /// to the conversion from scalar type ScalarTy to the Boolean type. CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { switch (ScalarTy->getScalarTypeKind()) { case Type::STK_Bool: return CK_NoOp; case Type::STK_CPointer: return CK_PointerToBoolean; case Type::STK_BlockPointer: return CK_PointerToBoolean; case Type::STK_ObjCObjectPointer: return CK_PointerToBoolean; case Type::STK_MemberPointer: return CK_MemberPointerToBoolean; case Type::STK_Integral: return CK_IntegralToBoolean; case Type::STK_Floating: return CK_FloatingToBoolean; case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean; case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean; } return CK_Invalid; } /// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { if (D->getMostRecentDecl()->isUsed()) return true; if (D->isExternallyVisible()) return true; if (const FunctionDecl *FD = dyn_cast(D)) { // If this is a function template and none of its specializations is used, // we should warn. if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate()) for (const auto *Spec : Template->specializations()) if (ShouldRemoveFromUnused(SemaRef, Spec)) return true; // UnusedFileScopedDecls stores the first declaration. // The declaration may have become definition so check again. const FunctionDecl *DeclToCheck; if (FD->hasBody(DeclToCheck)) return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); // Later redecls may add new information resulting in not having to warn, // so check again. DeclToCheck = FD->getMostRecentDecl(); if (DeclToCheck != FD) return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); } if (const VarDecl *VD = dyn_cast(D)) { // If a variable usable in constant expressions is referenced, // don't warn if it isn't used: if the value of a variable is required // for the computation of a constant expression, it doesn't make sense to // warn even if the variable isn't odr-used. (isReferenced doesn't // precisely reflect that, but it's a decent approximation.) if (VD->isReferenced() && VD->isUsableInConstantExpressions(SemaRef->Context)) return true; if (VarTemplateDecl *Template = VD->getDescribedVarTemplate()) // If this is a variable template and none of its specializations is used, // we should warn. for (const auto *Spec : Template->specializations()) if (ShouldRemoveFromUnused(SemaRef, Spec)) return true; // UnusedFileScopedDecls stores the first declaration. // The declaration may have become definition so check again. const VarDecl *DeclToCheck = VD->getDefinition(); if (DeclToCheck) return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); // Later redecls may add new information resulting in not having to warn, // so check again. DeclToCheck = VD->getMostRecentDecl(); if (DeclToCheck != VD) return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); } return false; } /// Obtains a sorted list of functions and variables that are undefined but /// ODR-used. void Sema::getUndefinedButUsed( SmallVectorImpl > &Undefined) { for (const auto &UndefinedUse : UndefinedButUsed) { NamedDecl *ND = UndefinedUse.first; // Ignore attributes that have become invalid. if (ND->isInvalidDecl()) continue; // __attribute__((weakref)) is basically a definition. if (ND->hasAttr()) continue; if (FunctionDecl *FD = dyn_cast(ND)) { if (FD->isDefined()) continue; if (FD->isExternallyVisible() && !FD->getMostRecentDecl()->isInlined()) continue; } else { auto *VD = cast(ND); if (VD->hasDefinition() != VarDecl::DeclarationOnly) continue; if (VD->isExternallyVisible() && !VD->getMostRecentDecl()->isInline()) continue; } Undefined.push_back(std::make_pair(ND, UndefinedUse.second)); } } /// checkUndefinedButUsed - Check for undefined objects with internal linkage /// or that are inline. static void checkUndefinedButUsed(Sema &S) { if (S.UndefinedButUsed.empty()) return; // Collect all the still-undefined entities with internal linkage. SmallVector, 16> Undefined; S.getUndefinedButUsed(Undefined); if (Undefined.empty()) return; for (SmallVectorImpl >::iterator I = Undefined.begin(), E = Undefined.end(); I != E; ++I) { NamedDecl *ND = I->first; if (ND->hasAttr() || ND->hasAttr()) { // An exported function will always be emitted when defined, so even if // the function is inline, it doesn't have to be emitted in this TU. An // imported function implies that it has been exported somewhere else. continue; } if (!ND->isExternallyVisible()) { S.Diag(ND->getLocation(), diag::warn_undefined_internal) << isa(ND) << ND; } else if (auto *FD = dyn_cast(ND)) { (void)FD; assert(FD->getMostRecentDecl()->isInlined() && "used object requires definition but isn't inline or internal?"); // FIXME: This is ill-formed; we should reject. S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND; } else { assert(cast(ND)->getMostRecentDecl()->isInline() && "used var requires definition but isn't inline or internal?"); S.Diag(ND->getLocation(), diag::err_undefined_inline_var) << ND; } if (I->second.isValid()) S.Diag(I->second, diag::note_used_here); } S.UndefinedButUsed.clear(); } void Sema::LoadExternalWeakUndeclaredIdentifiers() { if (!ExternalSource) return; SmallVector, 4> WeakIDs; ExternalSource->ReadWeakUndeclaredIdentifiers(WeakIDs); for (auto &WeakID : WeakIDs) WeakUndeclaredIdentifiers.insert(WeakID); } typedef llvm::DenseMap RecordCompleteMap; /// \brief Returns true, if all methods and nested classes of the given /// CXXRecordDecl are defined in this translation unit. /// /// Should only be called from ActOnEndOfTranslationUnit so that all /// definitions are actually read. static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD, RecordCompleteMap &MNCComplete) { RecordCompleteMap::iterator Cache = MNCComplete.find(RD); if (Cache != MNCComplete.end()) return Cache->second; if (!RD->isCompleteDefinition()) return false; bool Complete = true; for (DeclContext::decl_iterator I = RD->decls_begin(), E = RD->decls_end(); I != E && Complete; ++I) { if (const CXXMethodDecl *M = dyn_cast(*I)) Complete = M->isDefined() || (M->isPure() && !isa(M)); else if (const FunctionTemplateDecl *F = dyn_cast(*I)) // If the template function is marked as late template parsed at this // point, it has not been instantiated and therefore we have not // performed semantic analysis on it yet, so we cannot know if the type // can be considered complete. Complete = !F->getTemplatedDecl()->isLateTemplateParsed() && F->getTemplatedDecl()->isDefined(); else if (const CXXRecordDecl *R = dyn_cast(*I)) { if (R->isInjectedClassName()) continue; if (R->hasDefinition()) Complete = MethodsAndNestedClassesComplete(R->getDefinition(), MNCComplete); else Complete = false; } } MNCComplete[RD] = Complete; return Complete; } /// \brief Returns true, if the given CXXRecordDecl is fully defined in this /// translation unit, i.e. all methods are defined or pure virtual and all /// friends, friend functions and nested classes are fully defined in this /// translation unit. /// /// Should only be called from ActOnEndOfTranslationUnit so that all /// definitions are actually read. static bool IsRecordFullyDefined(const CXXRecordDecl *RD, RecordCompleteMap &RecordsComplete, RecordCompleteMap &MNCComplete) { RecordCompleteMap::iterator Cache = RecordsComplete.find(RD); if (Cache != RecordsComplete.end()) return Cache->second; bool Complete = MethodsAndNestedClassesComplete(RD, MNCComplete); for (CXXRecordDecl::friend_iterator I = RD->friend_begin(), E = RD->friend_end(); I != E && Complete; ++I) { // Check if friend classes and methods are complete. if (TypeSourceInfo *TSI = (*I)->getFriendType()) { // Friend classes are available as the TypeSourceInfo of the FriendDecl. if (CXXRecordDecl *FriendD = TSI->getType()->getAsCXXRecordDecl()) Complete = MethodsAndNestedClassesComplete(FriendD, MNCComplete); else Complete = false; } else { // Friend functions are available through the NamedDecl of FriendDecl. if (const FunctionDecl *FD = dyn_cast((*I)->getFriendDecl())) Complete = FD->isDefined(); else // This is a template friend, give up. Complete = false; } } RecordsComplete[RD] = Complete; return Complete; } void Sema::emitAndClearUnusedLocalTypedefWarnings() { if (ExternalSource) ExternalSource->ReadUnusedLocalTypedefNameCandidates( UnusedLocalTypedefNameCandidates); for (const TypedefNameDecl *TD : UnusedLocalTypedefNameCandidates) { if (TD->isReferenced()) continue; Diag(TD->getLocation(), diag::warn_unused_local_typedef) << isa(TD) << TD->getDeclName(); } UnusedLocalTypedefNameCandidates.clear(); } /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { assert(DelayedDiagnostics.getCurrentPool() == nullptr && "reached end of translation unit with a pool attached?"); // If code completion is enabled, don't perform any end-of-translation-unit // work. if (PP.isCodeCompletionEnabled()) return; // Complete translation units and modules define vtables and perform implicit // instantiations. PCH files do not. if (TUKind != TU_Prefix) { DiagnoseUseOfUnimplementedSelectors(); // If DefinedUsedVTables ends up marking any virtual member functions it // might lead to more pending template instantiations, which we then need // to instantiate. DefineUsedVTables(); // C++: Perform implicit template instantiations. // // FIXME: When we perform these implicit instantiations, we do not // carefully keep track of the point of instantiation (C++ [temp.point]). // This means that name lookup that occurs within the template // instantiation will always happen at the end of the translation unit, // so it will find some names that are not required to be found. This is // valid, but we could do better by diagnosing if an instantiation uses a // name that was not visible at its first point of instantiation. if (ExternalSource) { // Load pending instantiations from the external source. SmallVector Pending; ExternalSource->ReadPendingInstantiations(Pending); PendingInstantiations.insert(PendingInstantiations.begin(), Pending.begin(), Pending.end()); } PerformPendingInstantiations(); if (LateTemplateParserCleanup) LateTemplateParserCleanup(OpaqueParser); CheckDelayedMemberExceptionSpecs(); } DiagnoseUnterminatedPragmaAttribute(); // All delayed member exception specs should be checked or we end up accepting // incompatible declarations. // FIXME: This is wrong for TUKind == TU_Prefix. In that case, we need to // write out the lists to the AST file (if any). assert(DelayedDefaultedMemberExceptionSpecs.empty()); assert(DelayedExceptionSpecChecks.empty()); // All dllexport classes should have been processed already. assert(DelayedDllExportClasses.empty()); // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase( std::remove_if(UnusedFileScopedDecls.begin(nullptr, true), UnusedFileScopedDecls.end(), [this](const DeclaratorDecl *DD) { return ShouldRemoveFromUnused(this, DD); }), UnusedFileScopedDecls.end()); if (TUKind == TU_Prefix) { // Translation unit prefixes don't need any of the checking below. if (!PP.isIncrementalProcessingEnabled()) TUScope = nullptr; return; } // Check for #pragma weak identifiers that were never declared LoadExternalWeakUndeclaredIdentifiers(); for (auto WeakID : WeakUndeclaredIdentifiers) { if (WeakID.second.getUsed()) continue; Decl *PrevDecl = LookupSingleName(TUScope, WeakID.first, SourceLocation(), LookupOrdinaryName); if (PrevDecl != nullptr && !(isa(PrevDecl) || isa(PrevDecl))) Diag(WeakID.second.getLocation(), diag::warn_attribute_wrong_decl_type) << "'weak'" << ExpectedVariableOrFunction; else Diag(WeakID.second.getLocation(), diag::warn_weak_identifier_undeclared) << WeakID.first; } if (LangOpts.CPlusPlus11 && !Diags.isIgnored(diag::warn_delegating_ctor_cycle, SourceLocation())) CheckDelegatingCtorCycles(); if (!Diags.hasErrorOccurred()) { if (ExternalSource) ExternalSource->ReadUndefinedButUsed(UndefinedButUsed); checkUndefinedButUsed(*this); } if (TUKind == TU_Module) { // If we are building a module, resolve all of the exported declarations // now. if (Module *CurrentModule = PP.getCurrentModule()) { ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); SmallVector Stack; Stack.push_back(CurrentModule); while (!Stack.empty()) { Module *Mod = Stack.pop_back_val(); // Resolve the exported declarations and conflicts. // FIXME: Actually complain, once we figure out how to teach the // diagnostic client to deal with complaints in the module map at this // point. ModMap.resolveExports(Mod, /*Complain=*/false); ModMap.resolveUses(Mod, /*Complain=*/false); ModMap.resolveConflicts(Mod, /*Complain=*/false); // Queue the submodules, so their exports will also be resolved. Stack.append(Mod->submodule_begin(), Mod->submodule_end()); } } // Warnings emitted in ActOnEndOfTranslationUnit() should be emitted for // modules when they are built, not every time they are used. emitAndClearUnusedLocalTypedefWarnings(); // Modules don't need any of the checking below. TUScope = nullptr; return; } // C99 6.9.2p2: // A declaration of an identifier for an object that has file // scope without an initializer, and without a storage-class // specifier or with the storage-class specifier static, // constitutes a tentative definition. If a translation unit // contains one or more tentative definitions for an identifier, // and the translation unit contains no external definition for // that identifier, then the behavior is exactly as if the // translation unit contains a file scope declaration of that // identifier, with the composite type as of the end of the // translation unit, with an initializer equal to 0. llvm::SmallSet Seen; for (TentativeDefinitionsType::iterator T = TentativeDefinitions.begin(ExternalSource), TEnd = TentativeDefinitions.end(); T != TEnd; ++T) { VarDecl *VD = (*T)->getActingDefinition(); // If the tentative definition was completed, getActingDefinition() returns // null. If we've already seen this variable before, insert()'s second // return value is false. if (!VD || VD->isInvalidDecl() || !Seen.insert(VD).second) continue; if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(VD->getType())) { // Set the length of the array to 1 (C99 6.9.2p5). Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true); QualType T = Context.getConstantArrayType(ArrayT->getElementType(), One, ArrayType::Normal, 0); VD->setType(T); } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); // No initialization is performed for a tentative definition. CheckCompleteVariableDeclaration(VD); // Notify the consumer that we've completed a tentative definition. if (!VD->isInvalidDecl()) Consumer.CompleteTentativeDefinition(VD); } // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { // Output warning for unused file scoped decls. for (UnusedFileScopedDeclsType::iterator I = UnusedFileScopedDecls.begin(ExternalSource), E = UnusedFileScopedDecls.end(); I != E; ++I) { if (ShouldRemoveFromUnused(this, *I)) continue; if (const FunctionDecl *FD = dyn_cast(*I)) { const FunctionDecl *DiagD; if (!FD->hasBody(DiagD)) DiagD = FD; if (DiagD->isDeleted()) continue; // Deleted functions are supposed to be unused. if (DiagD->isReferenced()) { if (isa(DiagD)) Diag(DiagD->getLocation(), diag::warn_unneeded_member_function) << DiagD->getDeclName(); else { if (FD->getStorageClass() == SC_Static && !FD->isInlineSpecified() && !SourceMgr.isInMainFile( SourceMgr.getExpansionLoc(FD->getLocation()))) Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl) << DiagD->getDeclName(); else Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*function*/0 << DiagD->getDeclName(); } } else { if (FD->getDescribedFunctionTemplate()) Diag(DiagD->getLocation(), diag::warn_unused_template) << /*function*/0 << DiagD->getDeclName(); else Diag(DiagD->getLocation(), isa(DiagD) ? diag::warn_unused_member_function : diag::warn_unused_function) << DiagD->getDeclName(); } } else { const VarDecl *DiagD = cast(*I)->getDefinition(); if (!DiagD) DiagD = cast(*I); if (DiagD->isReferenced()) { Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*variable*/1 << DiagD->getDeclName(); } else if (DiagD->getType().isConstQualified()) { const SourceManager &SM = SourceMgr; if (SM.getMainFileID() != SM.getFileID(DiagD->getLocation()) || !PP.getLangOpts().IsHeaderFile) Diag(DiagD->getLocation(), diag::warn_unused_const_variable) << DiagD->getDeclName(); } else { if (DiagD->getDescribedVarTemplate()) Diag(DiagD->getLocation(), diag::warn_unused_template) << /*variable*/1 << DiagD->getDeclName(); else Diag(DiagD->getLocation(), diag::warn_unused_variable) << DiagD->getDeclName(); } } } emitAndClearUnusedLocalTypedefWarnings(); } if (!Diags.isIgnored(diag::warn_unused_private_field, SourceLocation())) { RecordCompleteMap RecordsComplete; RecordCompleteMap MNCComplete; for (NamedDeclSetType::iterator I = UnusedPrivateFields.begin(), E = UnusedPrivateFields.end(); I != E; ++I) { const NamedDecl *D = *I; const CXXRecordDecl *RD = dyn_cast(D->getDeclContext()); if (RD && !RD->isUnion() && IsRecordFullyDefined(RD, RecordsComplete, MNCComplete)) { Diag(D->getLocation(), diag::warn_unused_private_field) << D->getDeclName(); } } } if (!Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation())) { if (ExternalSource) ExternalSource->ReadMismatchingDeleteExpressions(DeleteExprs); for (const auto &DeletedFieldInfo : DeleteExprs) { for (const auto &DeleteExprLoc : DeletedFieldInfo.second) { AnalyzeDeleteExprMismatch(DeletedFieldInfo.first, DeleteExprLoc.first, DeleteExprLoc.second); } } } // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug. assert(ParsingInitForAutoVars.empty() && "Didn't unmark var as having its initializer parsed"); if (!PP.isIncrementalProcessingEnabled()) TUScope = nullptr; } //===----------------------------------------------------------------------===// // Helper functions. //===----------------------------------------------------------------------===// DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; while (true) { if (isa(DC) || isa(DC) || isa(DC)) { DC = DC->getParent(); } else if (isa(DC) && cast(DC)->getOverloadedOperator() == OO_Call && cast(DC->getParent())->isLambda()) { DC = DC->getParent()->getParent(); } else break; } return DC; } /// getCurFunctionDecl - If inside of a function body, this returns a pointer /// to the function decl for the function being parsed. If we're currently /// in a 'block', this returns the containing context. FunctionDecl *Sema::getCurFunctionDecl() { DeclContext *DC = getFunctionLevelDeclContext(); return dyn_cast(DC); } ObjCMethodDecl *Sema::getCurMethodDecl() { DeclContext *DC = getFunctionLevelDeclContext(); while (isa(DC)) DC = DC->getParent(); return dyn_cast(DC); } NamedDecl *Sema::getCurFunctionOrMethodDecl() { DeclContext *DC = getFunctionLevelDeclContext(); if (isa(DC) || isa(DC)) return cast(DC); return nullptr; } void Sema::EmitCurrentDiagnostic(unsigned DiagID) { // FIXME: It doesn't make sense to me that DiagID is an incoming argument here // and yet we also use the current diag ID on the DiagnosticsEngine. This has // been made more painfully obvious by the refactor that introduced this // function, but it is possible that the incoming argument can be // eliminated. If it truly cannot be (for example, there is some reentrancy // issue I am not seeing yet), then there should at least be a clarifying // comment somewhere. if (Optional Info = isSFINAEContext()) { switch (DiagnosticIDs::getDiagnosticSFINAEResponse( Diags.getCurrentDiagID())) { case DiagnosticIDs::SFINAE_Report: // We'll report the diagnostic below. break; case DiagnosticIDs::SFINAE_SubstitutionFailure: // Count this failure so that we know that template argument deduction // has failed. ++NumSFINAEErrors; // Make a copy of this suppressed diagnostic and store it with the // template-deduction information. if (*Info && !(*Info)->hasSFINAEDiagnostic()) { Diagnostic DiagInfo(&Diags); (*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(), PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); } Diags.setLastDiagnosticIgnored(); Diags.Clear(); return; case DiagnosticIDs::SFINAE_AccessControl: { // Per C++ Core Issue 1170, access control is part of SFINAE. // Additionally, the AccessCheckingSFINAE flag can be used to temporarily // make access control a part of SFINAE for the purposes of checking // type traits. if (!AccessCheckingSFINAE && !getLangOpts().CPlusPlus11) break; SourceLocation Loc = Diags.getCurrentDiagLoc(); // Suppress this diagnostic. ++NumSFINAEErrors; // Make a copy of this suppressed diagnostic and store it with the // template-deduction information. if (*Info && !(*Info)->hasSFINAEDiagnostic()) { Diagnostic DiagInfo(&Diags); (*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(), PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); } Diags.setLastDiagnosticIgnored(); Diags.Clear(); // Now the diagnostic state is clear, produce a C++98 compatibility // warning. Diag(Loc, diag::warn_cxx98_compat_sfinae_access_control); // The last diagnostic which Sema produced was ignored. Suppress any // notes attached to it. Diags.setLastDiagnosticIgnored(); return; } case DiagnosticIDs::SFINAE_Suppress: // Make a copy of this suppressed diagnostic and store it with the // template-deduction information; if (*Info) { Diagnostic DiagInfo(&Diags); (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(), PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); } // Suppress this diagnostic. Diags.setLastDiagnosticIgnored(); Diags.Clear(); return; } } // Set up the context's printing policy based on our current state. Context.setPrintingPolicy(getPrintingPolicy()); // Emit the diagnostic. if (!Diags.EmitCurrentDiagnostic()) return; // If this is not a note, and we're in a template instantiation // that is different from the last template instantiation where // we emitted an error, print a template instantiation // backtrace. if (!DiagnosticIDs::isBuiltinNote(DiagID)) PrintContextStack(); } Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID())); PD.Emit(Builder); return Builder; } /// \brief Looks through the macro-expansion chain for the given /// location, looking for a macro expansion with the given name. /// If one is found, returns true and sets the location to that /// expansion loc. bool Sema::findMacroSpelling(SourceLocation &locref, StringRef name) { SourceLocation loc = locref; if (!loc.isMacroID()) return false; // There's no good way right now to look at the intermediate // expansions, so just jump to the expansion location. loc = getSourceManager().getExpansionLoc(loc); // If that's written with the name, stop here. SmallVector buffer; if (getPreprocessor().getSpelling(loc, buffer) == name) { locref = loc; return true; } return false; } /// \brief Determines the active Scope associated with the given declaration /// context. /// /// This routine maps a declaration context to the active Scope object that /// represents that declaration context in the parser. It is typically used /// from "scope-less" code (e.g., template instantiation, lazy creation of /// declarations) that injects a name for name-lookup purposes and, therefore, /// must update the Scope. /// /// \returns The scope corresponding to the given declaraion context, or NULL /// if no such scope is open. Scope *Sema::getScopeForContext(DeclContext *Ctx) { if (!Ctx) return nullptr; Ctx = Ctx->getPrimaryContext(); for (Scope *S = getCurScope(); S; S = S->getParent()) { // Ignore scopes that cannot have declarations. This is important for // out-of-line definitions of static class members. if (S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) if (DeclContext *Entity = S->getEntity()) if (Ctx == Entity->getPrimaryContext()) return S; } return nullptr; } /// \brief Enter a new function scope void Sema::PushFunctionScope() { if (FunctionScopes.size() == 1) { // Use the "top" function scope rather than having to allocate // memory for a new scope. FunctionScopes.back()->Clear(); FunctionScopes.push_back(FunctionScopes.back()); if (LangOpts.OpenMP) pushOpenMPFunctionRegion(); return; } FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics())); if (LangOpts.OpenMP) pushOpenMPFunctionRegion(); } void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics(), BlockScope, Block)); } LambdaScopeInfo *Sema::PushLambdaScope() { LambdaScopeInfo *const LSI = new LambdaScopeInfo(getDiagnostics()); FunctionScopes.push_back(LSI); return LSI; } void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) { if (LambdaScopeInfo *const LSI = getCurLambda()) { LSI->AutoTemplateParameterDepth = Depth; return; } llvm_unreachable( "Remove assertion if intentionally called in a non-lambda context."); } void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, const Decl *D, const BlockExpr *blkExpr) { FunctionScopeInfo *Scope = FunctionScopes.pop_back_val(); assert(!FunctionScopes.empty() && "mismatched push/pop!"); if (LangOpts.OpenMP) popOpenMPFunctionRegion(Scope); // Issue any analysis-based warnings. if (WP && D) AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr); else for (const auto &PUD : Scope->PossiblyUnreachableDiags) Diag(PUD.Loc, PUD.PD); if (FunctionScopes.back() != Scope) delete Scope; } void Sema::PushCompoundScope() { getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo()); } void Sema::PopCompoundScope() { FunctionScopeInfo *CurFunction = getCurFunction(); assert(!CurFunction->CompoundScopes.empty() && "mismatched push/pop"); CurFunction->CompoundScopes.pop_back(); } /// \brief Determine whether any errors occurred within this function/method/ /// block. bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const { return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred(); } BlockScopeInfo *Sema::getCurBlock() { if (FunctionScopes.empty()) return nullptr; auto CurBSI = dyn_cast(FunctionScopes.back()); if (CurBSI && CurBSI->TheDecl && !CurBSI->TheDecl->Encloses(CurContext)) { // We have switched contexts due to template instantiation. assert(!CodeSynthesisContexts.empty()); return nullptr; } return CurBSI; } LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) { if (FunctionScopes.empty()) return nullptr; auto I = FunctionScopes.rbegin(); if (IgnoreNonLambdaCapturingScope) { auto E = FunctionScopes.rend(); while (I != E && isa(*I) && !isa(*I)) ++I; if (I == E) return nullptr; } auto *CurLSI = dyn_cast(*I); if (CurLSI && CurLSI->Lambda && !CurLSI->Lambda->Encloses(CurContext)) { // We have switched contexts due to template instantiation. assert(!CodeSynthesisContexts.empty()); return nullptr; } return CurLSI; } // We have a generic lambda if we parsed auto parameters, or we have // an associated template parameter list. LambdaScopeInfo *Sema::getCurGenericLambda() { if (LambdaScopeInfo *LSI = getCurLambda()) { return (LSI->AutoTemplateParams.size() || LSI->GLTemplateParameterList) ? LSI : nullptr; } return nullptr; } void Sema::ActOnComment(SourceRange Comment) { if (!LangOpts.RetainCommentsFromSystemHeaders && SourceMgr.isInSystemHeader(Comment.getBegin())) return; RawComment RC(SourceMgr, Comment, false, LangOpts.CommentOpts.ParseAllComments); if (RC.isAlmostTrailingComment()) { SourceRange MagicMarkerRange(Comment.getBegin(), Comment.getBegin().getLocWithOffset(3)); StringRef MagicMarkerText; switch (RC.getKind()) { case RawComment::RCK_OrdinaryBCPL: MagicMarkerText = "///<"; break; case RawComment::RCK_OrdinaryC: MagicMarkerText = "/**<"; break; default: llvm_unreachable("if this is an almost Doxygen comment, " "it should be ordinary"); } Diag(Comment.getBegin(), diag::warn_not_a_doxygen_trailing_member_comment) << FixItHint::CreateReplacement(MagicMarkerRange, MagicMarkerText); } Context.addComment(RC); } // Pin this vtable to this file. ExternalSemaSource::~ExternalSemaSource() {} void ExternalSemaSource::ReadMethodPool(Selector Sel) { } void ExternalSemaSource::updateOutOfDateSelector(Selector Sel) { } void ExternalSemaSource::ReadKnownNamespaces( SmallVectorImpl &Namespaces) { } void ExternalSemaSource::ReadUndefinedButUsed( llvm::MapVector &Undefined) {} void ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector, 4>> &) {} void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const { SourceLocation Loc = this->Loc; if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); if (Loc.isValid()) { Loc.print(OS, S.getSourceManager()); OS << ": "; } OS << Message; if (auto *ND = dyn_cast_or_null(TheDecl)) { OS << " '"; ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), true); OS << "'"; } OS << '\n'; } /// \brief Figure out if an expression could be turned into a call. /// /// Use this when trying to recover from an error where the programmer may have /// written just the name of a function instead of actually calling it. /// /// \param E - The expression to examine. /// \param ZeroArgCallReturnTy - If the expression can be turned into a call /// with no arguments, this parameter is set to the type returned by such a /// call; otherwise, it is set to an empty QualType. /// \param OverloadSet - If the expression is an overloaded function /// name, this parameter is populated with the decls of the various overloads. bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, UnresolvedSetImpl &OverloadSet) { ZeroArgCallReturnTy = QualType(); OverloadSet.clear(); const OverloadExpr *Overloads = nullptr; bool IsMemExpr = false; if (E.getType() == Context.OverloadTy) { OverloadExpr::FindResult FR = OverloadExpr::find(const_cast(&E)); // Ignore overloads that are pointer-to-member constants. if (FR.HasFormOfMemberPointer) return false; Overloads = FR.Expression; } else if (E.getType() == Context.BoundMemberTy) { Overloads = dyn_cast(E.IgnoreParens()); IsMemExpr = true; } bool Ambiguous = false; if (Overloads) { for (OverloadExpr::decls_iterator it = Overloads->decls_begin(), DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) { OverloadSet.addDecl(*it); // Check whether the function is a non-template, non-member which takes no // arguments. if (IsMemExpr) continue; if (const FunctionDecl *OverloadDecl = dyn_cast((*it)->getUnderlyingDecl())) { if (OverloadDecl->getMinRequiredArguments() == 0) { if (!ZeroArgCallReturnTy.isNull() && !Ambiguous) { ZeroArgCallReturnTy = QualType(); Ambiguous = true; } else ZeroArgCallReturnTy = OverloadDecl->getReturnType(); } } } // If it's not a member, use better machinery to try to resolve the call if (!IsMemExpr) return !ZeroArgCallReturnTy.isNull(); } // Attempt to call the member with no arguments - this will correctly handle // member templates with defaults/deduction of template arguments, overloads // with default arguments, etc. if (IsMemExpr && !E.isTypeDependent()) { bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); getDiagnostics().setSuppressAllDiagnostics(true); ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(), None, SourceLocation()); getDiagnostics().setSuppressAllDiagnostics(Suppress); if (R.isUsable()) { ZeroArgCallReturnTy = R.get()->getType(); return true; } return false; } if (const DeclRefExpr *DeclRef = dyn_cast(E.IgnoreParens())) { if (const FunctionDecl *Fun = dyn_cast(DeclRef->getDecl())) { if (Fun->getMinRequiredArguments() == 0) ZeroArgCallReturnTy = Fun->getReturnType(); return true; } } // We don't have an expression that's convenient to get a FunctionDecl from, // but we can at least check if the type is "function of 0 arguments". QualType ExprTy = E.getType(); const FunctionType *FunTy = nullptr; QualType PointeeTy = ExprTy->getPointeeType(); if (!PointeeTy.isNull()) FunTy = PointeeTy->getAs(); if (!FunTy) FunTy = ExprTy->getAs(); if (const FunctionProtoType *FPT = dyn_cast_or_null(FunTy)) { if (FPT->getNumParams() == 0) ZeroArgCallReturnTy = FunTy->getReturnType(); return true; } return false; } /// \brief Give notes for a set of overloads. /// /// A companion to tryExprAsCall. In cases when the name that the programmer /// wrote was an overloaded function, we may be able to make some guesses about /// plausible overloads based on their return types; such guesses can be handed /// off to this method to be emitted as notes. /// /// \param Overloads - The overloads to note. /// \param FinalNoteLoc - If we've suppressed printing some overloads due to /// -fshow-overloads=best, this is the location to attach to the note about too /// many candidates. Typically this will be the location of the original /// ill-formed expression. static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads, const SourceLocation FinalNoteLoc) { int ShownOverloads = 0; int SuppressedOverloads = 0; for (UnresolvedSetImpl::iterator It = Overloads.begin(), DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { // FIXME: Magic number for max shown overloads stolen from // OverloadCandidateSet::NoteCandidates. if (ShownOverloads >= 4 && S.Diags.getShowOverloads() == Ovl_Best) { ++SuppressedOverloads; continue; } NamedDecl *Fn = (*It)->getUnderlyingDecl(); S.Diag(Fn->getLocation(), diag::note_possible_target_of_call); ++ShownOverloads; } if (SuppressedOverloads) S.Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates) << SuppressedOverloads; } static void notePlausibleOverloads(Sema &S, SourceLocation Loc, const UnresolvedSetImpl &Overloads, bool (*IsPlausibleResult)(QualType)) { if (!IsPlausibleResult) return noteOverloads(S, Overloads, Loc); UnresolvedSet<2> PlausibleOverloads; for (OverloadExpr::decls_iterator It = Overloads.begin(), DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { const FunctionDecl *OverloadDecl = cast(*It); QualType OverloadResultTy = OverloadDecl->getReturnType(); if (IsPlausibleResult(OverloadResultTy)) PlausibleOverloads.addDecl(It.getDecl()); } noteOverloads(S, PlausibleOverloads, Loc); } /// Determine whether the given expression can be called by just /// putting parentheses after it. Notably, expressions with unary /// operators can't be because the unary operator will start parsing /// outside the call. static bool IsCallableWithAppend(Expr *E) { E = E->IgnoreImplicit(); return (!isa(E) && !isa(E) && !isa(E) && !isa(E)); } bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain, bool (*IsPlausibleResult)(QualType)) { SourceLocation Loc = E.get()->getExprLoc(); SourceRange Range = E.get()->getSourceRange(); QualType ZeroArgCallTy; UnresolvedSet<4> Overloads; if (tryExprAsCall(*E.get(), ZeroArgCallTy, Overloads) && !ZeroArgCallTy.isNull() && (!IsPlausibleResult || IsPlausibleResult(ZeroArgCallTy))) { // At this point, we know E is potentially callable with 0 // arguments and that it returns something of a reasonable type, // so we can emit a fixit and carry on pretending that E was // actually a CallExpr. SourceLocation ParenInsertionLoc = getLocForEndOfToken(Range.getEnd()); Diag(Loc, PD) << /*zero-arg*/ 1 << Range << (IsCallableWithAppend(E.get()) ? FixItHint::CreateInsertion(ParenInsertionLoc, "()") : FixItHint()); notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. E = ActOnCallExpr(nullptr, E.get(), Range.getEnd(), None, Range.getEnd().getLocWithOffset(1)); return true; } if (!ForceComplain) return false; Diag(Loc, PD) << /*not zero-arg*/ 0 << Range; notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); E = ExprError(); return true; } IdentifierInfo *Sema::getSuperIdentifier() const { if (!Ident_super) Ident_super = &Context.Idents.get("super"); return Ident_super; } IdentifierInfo *Sema::getFloat128Identifier() const { if (!Ident___float128) Ident___float128 = &Context.Idents.get("__float128"); return Ident___float128; } void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K) { CapturingScopeInfo *CSI = new CapturedRegionScopeInfo( getDiagnostics(), S, CD, RD, CD->getContextParam(), K, (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0); CSI->ReturnType = Context.VoidTy; FunctionScopes.push_back(CSI); } CapturedRegionScopeInfo *Sema::getCurCapturedRegion() { if (FunctionScopes.empty()) return nullptr; return dyn_cast(FunctionScopes.back()); } const llvm::MapVector & Sema::getMismatchingDeleteExpressions() const { return DeleteExprs; } void Sema::setOpenCLExtensionForType(QualType T, llvm::StringRef ExtStr) { if (ExtStr.empty()) return; llvm::SmallVector Exts; ExtStr.split(Exts, " ", /* limit */ -1, /* keep empty */ false); auto CanT = T.getCanonicalType().getTypePtr(); for (auto &I : Exts) OpenCLTypeExtMap[CanT].insert(I.str()); } void Sema::setOpenCLExtensionForDecl(Decl *FD, StringRef ExtStr) { llvm::SmallVector Exts; ExtStr.split(Exts, " ", /* limit */ -1, /* keep empty */ false); if (Exts.empty()) return; for (auto &I : Exts) OpenCLDeclExtMap[FD].insert(I.str()); } void Sema::setCurrentOpenCLExtensionForType(QualType T) { if (CurrOpenCLExtension.empty()) return; setOpenCLExtensionForType(T, CurrOpenCLExtension); } void Sema::setCurrentOpenCLExtensionForDecl(Decl *D) { if (CurrOpenCLExtension.empty()) return; setOpenCLExtensionForDecl(D, CurrOpenCLExtension); } bool Sema::isOpenCLDisabledDecl(Decl *FD) { auto Loc = OpenCLDeclExtMap.find(FD); if (Loc == OpenCLDeclExtMap.end()) return false; for (auto &I : Loc->second) { if (!getOpenCLOptions().isEnabled(I)) return true; } return false; } template bool Sema::checkOpenCLDisabledTypeOrDecl(T D, DiagLocT DiagLoc, DiagInfoT DiagInfo, MapT &Map, unsigned Selector, SourceRange SrcRange) { auto Loc = Map.find(D); if (Loc == Map.end()) return false; bool Disabled = false; for (auto &I : Loc->second) { if (I != CurrOpenCLExtension && !getOpenCLOptions().isEnabled(I)) { Diag(DiagLoc, diag::err_opencl_requires_extension) << Selector << DiagInfo << I << SrcRange; Disabled = true; } } return Disabled; } bool Sema::checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType QT) { // Check extensions for declared types. Decl *Decl = nullptr; if (auto TypedefT = dyn_cast(QT.getTypePtr())) Decl = TypedefT->getDecl(); if (auto TagT = dyn_cast(QT.getCanonicalType().getTypePtr())) Decl = TagT->getDecl(); auto Loc = DS.getTypeSpecTypeLoc(); if (checkOpenCLDisabledTypeOrDecl(Decl, Loc, QT, OpenCLDeclExtMap)) return true; // Check extensions for builtin types. return checkOpenCLDisabledTypeOrDecl(QT.getCanonicalType().getTypePtr(), Loc, QT, OpenCLTypeExtMap); } bool Sema::checkOpenCLDisabledDecl(const Decl &D, const Expr &E) { return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), "", OpenCLDeclExtMap, 1, D.getSourceRange()); } Index: vendor/clang/dist/lib/Sema/SemaDecl.cpp =================================================================== --- vendor/clang/dist/lib/Sema/SemaDecl.cpp (revision 318415) +++ vendor/clang/dist/lib/Sema/SemaDecl.cpp (revision 318416) @@ -1,16197 +1,16212 @@ //===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements semantic analysis for declarations. // //===----------------------------------------------------------------------===// #include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/CommentDiagnostic.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/HeaderSearch.h" // TODO: Sema shouldn't depend on Lex #include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering. #include "clang/Lex/ModuleLoader.h" // TODO: Sema shouldn't depend on Lex #include "clang/Lex/Preprocessor.h" // Included for isCodeCompletionEnabled() #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Triple.h" #include #include #include using namespace clang; using namespace sema; Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) { if (OwnedType) { Decl *Group[2] = { OwnedType, Ptr }; return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, 2)); } return DeclGroupPtrTy::make(DeclGroupRef(Ptr)); } namespace { class TypeNameValidatorCCC : public CorrectionCandidateCallback { public: TypeNameValidatorCCC(bool AllowInvalid, bool WantClass = false, bool AllowTemplates = false, bool AllowNonTemplates = true) : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass), AllowTemplates(AllowTemplates), AllowNonTemplates(AllowNonTemplates) { WantExpressionKeywords = false; WantCXXNamedCasts = false; WantRemainingKeywords = false; } bool ValidateCandidate(const TypoCorrection &candidate) override { if (NamedDecl *ND = candidate.getCorrectionDecl()) { if (!AllowInvalidDecl && ND->isInvalidDecl()) return false; if (getAsTypeTemplateDecl(ND)) return AllowTemplates; bool IsType = isa(ND) || isa(ND); if (!IsType) return false; if (AllowNonTemplates) return true; // An injected-class-name of a class template (specialization) is valid // as a template or as a non-template. if (AllowTemplates) { auto *RD = dyn_cast(ND); if (!RD || !RD->isInjectedClassName()) return false; RD = cast(RD->getDeclContext()); return RD->getDescribedClassTemplate() || isa(RD); } return false; } return !WantClassName && candidate.isKeyword(); } private: bool AllowInvalidDecl; bool WantClassName; bool AllowTemplates; bool AllowNonTemplates; }; } // end anonymous namespace /// \brief Determine whether the token kind starts a simple-type-specifier. bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { switch (Kind) { // FIXME: Take into account the current language when deciding whether a // token kind is a valid type specifier case tok::kw_short: case tok::kw_long: case tok::kw___int64: case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_void: case tok::kw_char: case tok::kw_int: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw___float128: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: case tok::kw___auto_type: return true; case tok::annot_typename: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_typeof: case tok::annot_decltype: case tok::kw_decltype: return getLangOpts().CPlusPlus; default: break; } return false; } namespace { enum class UnqualifiedTypeNameLookupResult { NotFound, FoundNonType, FoundType }; } // end anonymous namespace /// \brief Tries to perform unqualified lookup of the type decls in bases for /// dependent class. /// \return \a NotFound if no any decls is found, \a FoundNotType if found not a /// type decl, \a FoundType if only type decls are found. static UnqualifiedTypeNameLookupResult lookupUnqualifiedTypeNameInBase(Sema &S, const IdentifierInfo &II, SourceLocation NameLoc, const CXXRecordDecl *RD) { if (!RD->hasDefinition()) return UnqualifiedTypeNameLookupResult::NotFound; // Look for type decls in base classes. UnqualifiedTypeNameLookupResult FoundTypeDecl = UnqualifiedTypeNameLookupResult::NotFound; for (const auto &Base : RD->bases()) { const CXXRecordDecl *BaseRD = nullptr; if (auto *BaseTT = Base.getType()->getAs()) BaseRD = BaseTT->getAsCXXRecordDecl(); else if (auto *TST = Base.getType()->getAs()) { // Look for type decls in dependent base classes that have known primary // templates. if (!TST || !TST->isDependentType()) continue; auto *TD = TST->getTemplateName().getAsTemplateDecl(); if (!TD) continue; if (auto *BasePrimaryTemplate = dyn_cast_or_null(TD->getTemplatedDecl())) { if (BasePrimaryTemplate->getCanonicalDecl() != RD->getCanonicalDecl()) BaseRD = BasePrimaryTemplate; else if (auto *CTD = dyn_cast(TD)) { if (const ClassTemplatePartialSpecializationDecl *PS = CTD->findPartialSpecialization(Base.getType())) if (PS->getCanonicalDecl() != RD->getCanonicalDecl()) BaseRD = PS; } } } if (BaseRD) { for (NamedDecl *ND : BaseRD->lookup(&II)) { if (!isa(ND)) return UnqualifiedTypeNameLookupResult::FoundNonType; FoundTypeDecl = UnqualifiedTypeNameLookupResult::FoundType; } if (FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound) { switch (lookupUnqualifiedTypeNameInBase(S, II, NameLoc, BaseRD)) { case UnqualifiedTypeNameLookupResult::FoundNonType: return UnqualifiedTypeNameLookupResult::FoundNonType; case UnqualifiedTypeNameLookupResult::FoundType: FoundTypeDecl = UnqualifiedTypeNameLookupResult::FoundType; break; case UnqualifiedTypeNameLookupResult::NotFound: break; } } } } return FoundTypeDecl; } static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, const IdentifierInfo &II, SourceLocation NameLoc) { // Lookup in the parent class template context, if any. const CXXRecordDecl *RD = nullptr; UnqualifiedTypeNameLookupResult FoundTypeDecl = UnqualifiedTypeNameLookupResult::NotFound; for (DeclContext *DC = S.CurContext; DC && FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound; DC = DC->getParent()) { // Look for type decls in dependent base classes that have known primary // templates. RD = dyn_cast(DC); if (RD && RD->getDescribedClassTemplate()) FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD); } if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType) return nullptr; // We found some types in dependent base classes. Recover as if the user // wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the // lookup during template instantiation. S.Diag(NameLoc, diag::ext_found_via_dependent_bases_lookup) << &II; ASTContext &Context = S.Context; auto *NNS = NestedNameSpecifier::Create(Context, nullptr, false, cast(Context.getRecordType(RD))); QualType T = Context.getDependentNameType(ETK_Typename, NNS, &II); CXXScopeSpec SS; SS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); TypeLocBuilder Builder; DependentNameTypeLoc DepTL = Builder.push(T); DepTL.setNameLoc(NameLoc); DepTL.setElaboratedKeywordLoc(SourceLocation()); DepTL.setQualifierLoc(SS.getWithLocInContext(Context)); return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } /// \brief If the identifier refers to a type name within this scope, /// return the declaration of that type. /// /// This routine performs ordinary name lookup of the identifier II /// within the given scope, with optional C++ scope specifier SS, to /// determine whether the name refers to a type. If so, returns an /// opaque pointer (actually a QualType) corresponding to that /// type. Otherwise, returns NULL. ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr, bool IsCtorOrDtorName, bool WantNontrivialTypeSourceInfo, bool IsClassTemplateDeductionContext, IdentifierInfo **CorrectedII) { // FIXME: Consider allowing this outside C++1z mode as an extension. bool AllowDeducedTemplate = IsClassTemplateDeductionContext && getLangOpts().CPlusPlus1z && !IsCtorOrDtorName && !isClassName && !HasTrailingDot; // Determine where we will perform name lookup. DeclContext *LookupCtx = nullptr; if (ObjectTypePtr) { QualType ObjectType = ObjectTypePtr.get(); if (ObjectType->isRecordType()) LookupCtx = computeDeclContext(ObjectType); } else if (SS && SS->isNotEmpty()) { LookupCtx = computeDeclContext(*SS, false); if (!LookupCtx) { if (isDependentScopeSpecifier(*SS)) { // C++ [temp.res]p3: // A qualified-id that refers to a type and in which the // nested-name-specifier depends on a template-parameter (14.6.2) // shall be prefixed by the keyword typename to indicate that the // qualified-id denotes a type, forming an // elaborated-type-specifier (7.1.5.3). // // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. if (!isClassName && !IsCtorOrDtorName) return nullptr; // We know from the grammar that this name refers to a type, // so build a dependent node to describe the type. if (WantNontrivialTypeSourceInfo) return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get(); NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context); QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc, II, NameLoc); return ParsedType::make(T); } return nullptr; } if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS, LookupCtx)) return nullptr; } // FIXME: LookupNestedNameSpecifierName isn't the right kind of // lookup for class-names. LookupNameKind Kind = isClassName ? LookupNestedNameSpecifierName : LookupOrdinaryName; LookupResult Result(*this, &II, NameLoc, Kind); if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. LookupQualifiedName(Result, LookupCtx); if (ObjectTypePtr && Result.empty()) { // C++ [basic.lookup.classref]p3: // If the unqualified-id is ~type-name, the type-name is looked up // in the context of the entire postfix-expression. If the type T of // the object expression is of a class type C, the type-name is also // looked up in the scope of class C. At least one of the lookups shall // find a name that refers to (possibly cv-qualified) T. LookupName(Result, S); } } else { // Perform unqualified name lookup. LookupName(Result, S); // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty())) { if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(*this, II, NameLoc)) return TypeInBase; } } NamedDecl *IIDecl = nullptr; switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: if (CorrectedII) { TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), Kind, S, SS, llvm::make_unique( true, isClassName, AllowDeducedTemplate), CTK_ErrorRecovery); IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); TemplateTy Template; bool MemberOfUnknownSpecialization; UnqualifiedId TemplateName; TemplateName.setIdentifier(NewII, NameLoc); NestedNameSpecifier *NNS = Correction.getCorrectionSpecifier(); CXXScopeSpec NewSS, *NewSSPtr = SS; if (SS && NNS) { NewSS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); NewSSPtr = &NewSS; } if (Correction && (NNS || NewII != &II) && // Ignore a correction to a template type as the to-be-corrected // identifier is not a template (typo correction for template names // is handled elsewhere). !(getLangOpts().CPlusPlus && NewSSPtr && isTemplateName(S, *NewSSPtr, false, TemplateName, nullptr, false, Template, MemberOfUnknownSpecialization))) { ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr, isClassName, HasTrailingDot, ObjectTypePtr, IsCtorOrDtorName, WantNontrivialTypeSourceInfo, IsClassTemplateDeductionContext); if (Ty) { diagnoseTypo(Correction, PDiag(diag::err_unknown_type_or_class_name_suggest) << Result.getLookupName() << isClassName); if (SS && NNS) SS->MakeTrivial(Context, NNS, SourceRange(NameLoc)); *CorrectedII = NewII; return Ty; } } } // If typo correction failed or was not performed, fall through case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: Result.suppressDiagnostics(); return nullptr; case LookupResult::Ambiguous: // Recover from type-hiding ambiguities by hiding the type. We'll // do the lookup again when looking for an object, and we can // diagnose the error then. If we don't do this, then the error // about hiding the type will be immediately followed by an error // that only makes sense if the identifier was treated like a type. if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) { Result.suppressDiagnostics(); return nullptr; } // Look to see if we have a type anywhere in the list of results. for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end(); Res != ResEnd; ++Res) { if (isa(*Res) || isa(*Res) || (AllowDeducedTemplate && getAsTypeTemplateDecl(*Res))) { if (!IIDecl || (*Res)->getLocation().getRawEncoding() < IIDecl->getLocation().getRawEncoding()) IIDecl = *Res; } } if (!IIDecl) { // None of the entities we found is a type, so there is no way // to even assume that the result is a type. In this case, don't // complain about the ambiguity. The parser will either try to // perform this lookup again (e.g., as an object name), which // will produce the ambiguity, or will complain that it expected // a type name. Result.suppressDiagnostics(); return nullptr; } // We found a type within the ambiguous lookup; diagnose the // ambiguity and then return that type. This might be the right // answer, or it might not be, but it suppresses any attempt to // perform the name lookup again. break; case LookupResult::Found: IIDecl = Result.getFoundDecl(); break; } assert(IIDecl && "Didn't find decl"); QualType T; if (TypeDecl *TD = dyn_cast(IIDecl)) { // C++ [class.qual]p2: A lookup that would find the injected-class-name // instead names the constructors of the class, except when naming a class. // This is ill-formed when we're not actually forming a ctor or dtor name. auto *LookupRD = dyn_cast_or_null(LookupCtx); auto *FoundRD = dyn_cast(TD); if (!isClassName && !IsCtorOrDtorName && LookupRD && FoundRD && FoundRD->isInjectedClassName() && declaresSameEntity(LookupRD, cast(FoundRD->getParent()))) Diag(NameLoc, diag::err_out_of_line_qualified_id_type_names_constructor) << &II << /*Type*/1; DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getTypeDeclType(TD); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); if (!HasTrailingDot) T = Context.getObjCInterfaceType(IDecl); } else if (AllowDeducedTemplate) { if (auto *TD = getAsTypeTemplateDecl(IIDecl)) T = Context.getDeducedTemplateSpecializationType(TemplateName(TD), QualType(), false); } if (T.isNull()) { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); return nullptr; } // NOTE: avoid constructing an ElaboratedType(Loc) if this is a // constructor or destructor name (in such a case, the scope specifier // will be attached to the enclosing Expr or Decl node). if (SS && SS->isNotEmpty() && !IsCtorOrDtorName && !isa(IIDecl)) { if (WantNontrivialTypeSourceInfo) { // Construct a type with type-source information. TypeLocBuilder Builder; Builder.pushTypeSpec(T).setNameLoc(NameLoc); T = getElaboratedType(ETK_None, *SS, T); ElaboratedTypeLoc ElabTL = Builder.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS->getWithLocInContext(Context)); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } else { T = getElaboratedType(ETK_None, *SS, T); } } return ParsedType::make(T); } // Builds a fake NNS for the given decl context. static NestedNameSpecifier * synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) { for (;; DC = DC->getLookupParent()) { DC = DC->getPrimaryContext(); auto *ND = dyn_cast(DC); if (ND && !ND->isInline() && !ND->isAnonymousNamespace()) return NestedNameSpecifier::Create(Context, nullptr, ND); else if (auto *RD = dyn_cast(DC)) return NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(), RD->getTypeForDecl()); else if (isa(DC)) return NestedNameSpecifier::GlobalSpecifier(Context); } llvm_unreachable("something isn't in TU scope?"); } /// Find the parent class with dependent bases of the innermost enclosing method /// context. Do not look for enclosing CXXRecordDecls directly, or we will end /// up allowing unqualified dependent type names at class-level, which MSVC /// correctly rejects. static const CXXRecordDecl * findRecordWithDependentBasesOfEnclosingMethod(const DeclContext *DC) { for (; DC && DC->isDependentContext(); DC = DC->getLookupParent()) { DC = DC->getPrimaryContext(); if (const auto *MD = dyn_cast(DC)) if (MD->getParent()->hasAnyDependentBases()) return MD->getParent(); } return nullptr; } ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II, SourceLocation NameLoc, bool IsTemplateTypeArg) { assert(getLangOpts().MSVCCompat && "shouldn't be called in non-MSVC mode"); NestedNameSpecifier *NNS = nullptr; if (IsTemplateTypeArg && getCurScope()->isTemplateParamScope()) { // If we weren't able to parse a default template argument, delay lookup // until instantiation time by making a non-dependent DependentTypeName. We // pretend we saw a NestedNameSpecifier referring to the current scope, and // lookup is retried. // FIXME: This hurts our diagnostic quality, since we get errors like "no // type named 'Foo' in 'current_namespace'" when the user didn't write any // name specifiers. NNS = synthesizeCurrentNestedNameSpecifier(Context, CurContext); Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II; } else if (const CXXRecordDecl *RD = findRecordWithDependentBasesOfEnclosingMethod(CurContext)) { // Build a DependentNameType that will perform lookup into RD at // instantiation time. NNS = NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(), RD->getTypeForDecl()); // Diagnose that this identifier was undeclared, and retry the lookup during // template instantiation. Diag(NameLoc, diag::ext_undeclared_unqual_id_with_dependent_base) << &II << RD; } else { // This is not a situation that we should recover from. return ParsedType(); } QualType T = Context.getDependentNameType(ETK_None, NNS, &II); // Build type location information. We synthesized the qualifier, so we have // to build a fake NestedNameSpecifierLoc. NestedNameSpecifierLocBuilder NNSLocBuilder; NNSLocBuilder.MakeTrivial(Context, NNS, SourceRange(NameLoc)); NestedNameSpecifierLoc QualifierLoc = NNSLocBuilder.getWithLocInContext(Context); TypeLocBuilder Builder; DependentNameTypeLoc DepTL = Builder.push(T); DepTL.setNameLoc(NameLoc); DepTL.setElaboratedKeywordLoc(SourceLocation()); DepTL.setQualifierLoc(QualifierLoc); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If /// so, this returns the TST for the tag corresponding to it (TST_enum, /// TST_union, TST_struct, TST_interface, TST_class). This is used to diagnose /// cases in C where the user forgot to specify the tag. DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { // Do a tag name lookup in this scope. LookupResult R(*this, &II, SourceLocation(), LookupTagName); LookupName(R, S, false); R.suppressDiagnostics(); if (R.getResultKind() == LookupResult::Found) if (const TagDecl *TD = R.getAsSingle()) { switch (TD->getTagKind()) { case TTK_Struct: return DeclSpec::TST_struct; case TTK_Interface: return DeclSpec::TST_interface; case TTK_Union: return DeclSpec::TST_union; case TTK_Class: return DeclSpec::TST_class; case TTK_Enum: return DeclSpec::TST_enum; } } return DeclSpec::TST_unspecified; } /// isMicrosoftMissingTypename - In Microsoft mode, within class scope, /// if a CXXScopeSpec's type is equal to the type of one of the base classes /// then downgrade the missing typename error to a warning. /// This is needed for MSVC compatibility; Example: /// @code /// template class A { /// public: /// typedef int TYPE; /// }; /// template class B : public A { /// public: /// A::TYPE a; // no typename required because A is a base class. /// }; /// @endcode bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (CurContext->isRecord()) { if (SS->getScopeRep()->getKind() == NestedNameSpecifier::Super) return true; const Type *Ty = SS->getScopeRep()->getAsType(); CXXRecordDecl *RD = cast(CurContext); for (const auto &Base : RD->bases()) if (Ty && Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType())) return true; return S->isFunctionPrototypeScope(); } return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, bool IsTemplateName) { // Don't report typename errors for editor placeholders. if (II->isEditorPlaceholder()) return; // We don't have anything to suggest (yet). SuggestedType = nullptr; // There may have been a typo in the name of the type. Look up typo // results, in case we have something that we can suggest. if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS, llvm::make_unique( false, false, IsTemplateName, !IsTemplateName), CTK_ErrorRecovery)) { // FIXME: Support error recovery for the template-name case. bool CanRecover = !IsTemplateName; if (Corrected.isKeyword()) { // We corrected to a keyword. diagnoseTypo(Corrected, PDiag(IsTemplateName ? diag::err_no_template_suggest : diag::err_unknown_typename_suggest) << II); II = Corrected.getCorrectionAsIdentifierInfo(); } else { // We found a similarly-named type or interface; suggest that. if (!SS || !SS->isSet()) { diagnoseTypo(Corrected, PDiag(IsTemplateName ? diag::err_no_template_suggest : diag::err_unknown_typename_suggest) << II, CanRecover); } else if (DeclContext *DC = computeDeclContext(*SS, false)) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && II->getName().equals(CorrectedStr); diagnoseTypo(Corrected, PDiag(IsTemplateName ? diag::err_no_member_template_suggest : diag::err_unknown_nested_typename_suggest) << II << DC << DroppedSpecifier << SS->getRange(), CanRecover); } else { llvm_unreachable("could not have corrected a typo here"); } if (!CanRecover) return; CXXScopeSpec tmpSS; if (Corrected.getCorrectionSpecifier()) tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), SourceRange(IILoc)); // FIXME: Support class template argument deduction here. SuggestedType = getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S, tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr, /*IsCtorOrDtorName=*/false, /*NonTrivialTypeSourceInfo=*/true); } return; } if (getLangOpts().CPlusPlus && !IsTemplateName) { // See if II is a class template that the user forgot to pass arguments to. UnqualifiedId Name; Name.setIdentifier(II, IILoc); CXXScopeSpec EmptySS; TemplateTy TemplateResult; bool MemberOfUnknownSpecialization; if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false, Name, nullptr, true, TemplateResult, MemberOfUnknownSpecialization) == TNK_Type_template) { TemplateName TplName = TemplateResult.get(); Diag(IILoc, diag::err_template_missing_args) << (int)getTemplateNameKindForDiagnostics(TplName) << TplName; if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { Diag(TplDecl->getLocation(), diag::note_template_decl_here) << TplDecl->getTemplateParameters()->getSourceRange(); } return; } } // FIXME: Should we move the logic that tries to recover from a missing tag // (struct, union, enum) from Parser::ParseImplicitInt here, instead? if (!SS || (!SS->isSet() && !SS->isInvalid())) Diag(IILoc, IsTemplateName ? diag::err_no_template : diag::err_unknown_typename) << II; else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, IsTemplateName ? diag::err_no_member_template : diag::err_typename_nested_not_found) << II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S)) DiagID = diag::ext_typename_missing; Diag(SS->getRange().getBegin(), DiagID) << SS->getScopeRep() << II->getName() << SourceRange(SS->getRange().getBegin(), IILoc) << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename "); SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, *II, IILoc).get(); } else { assert(SS && SS->isInvalid() && "Invalid scope specifier has already been diagnosed"); } } /// \brief Determine whether the given result set contains either a type name /// or static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) { bool CheckTemplate = R.getSema().getLangOpts().CPlusPlus && NextToken.is(tok::less); for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) { if (isa(*I) || isa(*I)) return true; if (CheckTemplate && isa(*I)) return true; } return false; } static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); SemaRef.LookupParsedName(R, S, &SS); if (TagDecl *Tag = R.getAsSingle()) { StringRef FixItTagName; switch (Tag->getTagKind()) { case TTK_Class: FixItTagName = "class "; break; case TTK_Enum: FixItTagName = "enum "; break; case TTK_Struct: FixItTagName = "struct "; break; case TTK_Interface: FixItTagName = "__interface "; break; case TTK_Union: FixItTagName = "union "; break; } StringRef TagName = FixItTagName.drop_back(); SemaRef.Diag(NameLoc, diag::err_use_of_tag_name_without_tag) << Name << TagName << SemaRef.getLangOpts().CPlusPlus << FixItHint::CreateInsertion(NameLoc, FixItTagName); for (LookupResult::iterator I = Result.begin(), IEnd = Result.end(); I != IEnd; ++I) SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) << Name << TagName; // Replace lookup results with just the tag decl. Result.clear(Sema::LookupTagName); SemaRef.LookupParsedName(Result, S, &SS); return true; } return false; } /// Build a ParsedType for a simple-type-specifier with a nested-name-specifier. static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, QualType T, SourceLocation NameLoc) { ASTContext &Context = S.Context; TypeLocBuilder Builder; Builder.pushTypeSpec(T).setNameLoc(NameLoc); T = S.getElaboratedType(ETK_None, SS, T); ElaboratedTypeLoc ElabTL = Builder.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken, bool IsAddressOfOperand, std::unique_ptr CCC) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); if (NextToken.is(tok::coloncolon)) { NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation()); BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false); } else if (getLangOpts().CPlusPlus && SS.isSet() && isCurrentClassName(*Name, S, &SS)) { // Per [class.qual]p2, this names the constructors of SS, not the // injected-class-name. We don't have a classification for that. // There's not much point caching this result, since the parser // will reject it later. return NameClassification::Unknown(); } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); LookupParsedName(Result, S, &SS, !CurMethod); // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) { if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(*this, *Name, NameLoc)) return TypeInBase; } // Perform lookup for Objective-C instance variables (including automatically // synthesized instance variables), if we're in an Objective-C method. // FIXME: This lookup really, really needs to be folded in to the normal // unqualified lookup mechanism. if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) { ExprResult E = LookupInObjCMethod(Result, S, Name, true); if (E.get() || E.isInvalid()) return E; } bool SecondTry = false; bool IsFilteredTemplateName = false; Corrected: switch (Result.getResultKind()) { case LookupResult::NotFound: // If an unqualified-id is followed by a '(', then we have a function // call. if (!SS.isSet() && NextToken.is(tok::l_paren)) { // In C++, this is an ADL-only call. // FIXME: Reference? if (getLangOpts().CPlusPlus) return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); // C90 6.3.2.2: // If the expression that precedes the parenthesized argument list in a // function call consists solely of an identifier, and if no // declaration is visible for this identifier, the identifier is // implicitly declared exactly as if, in the innermost block containing // the function call, the declaration // // extern int identifier (); // // appeared. // // We also allow this in C99 as an extension. if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) { Result.addDecl(D); Result.resolveKind(); return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false); } } // In C, we first see whether there is a tag type by the same name, in // which case it's likely that the user just forgot to write "enum", // "struct", or "union". if (!getLangOpts().CPlusPlus && !SecondTry && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { break; } // Perform typo correction to determine if there is another name that is // close to this name. if (!SecondTry && CCC) { SecondTry = true; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, &SS, std::move(CCC), CTK_ErrorRecovery)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; NamedDecl *FirstDecl = Corrected.getFoundDecl(); NamedDecl *UnderlyingFirstDecl = Corrected.getCorrectionDecl(); if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && UnderlyingFirstDecl && isa(UnderlyingFirstDecl)) { UnqualifiedDiag = diag::err_no_template_suggest; QualifiedDiag = diag::err_no_member_template_suggest; } else if (UnderlyingFirstDecl && (isa(UnderlyingFirstDecl) || isa(UnderlyingFirstDecl) || isa(UnderlyingFirstDecl))) { UnqualifiedDiag = diag::err_unknown_typename_suggest; QualifiedDiag = diag::err_unknown_nested_typename_suggest; } if (SS.isEmpty()) { diagnoseTypo(Corrected, PDiag(UnqualifiedDiag) << Name); } else {// FIXME: is this even reachable? Test it. std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name->getName().equals(CorrectedStr); diagnoseTypo(Corrected, PDiag(QualifiedDiag) << Name << computeDeclContext(SS, false) << DroppedSpecifier << SS.getRange()); } // Update the name, so that the caller has the new name. Name = Corrected.getCorrectionAsIdentifierInfo(); // Typo correction corrected to a keyword. if (Corrected.isKeyword()) return Name; // Also update the LookupResult... // FIXME: This should probably go away at some point Result.clear(); Result.setLookupName(Corrected.getCorrection()); if (FirstDecl) Result.addDecl(FirstDecl); // If we found an Objective-C instance variable, let // LookupInObjCMethod build the appropriate expression to // reference the ivar. // FIXME: This is a gross hack. if (ObjCIvarDecl *Ivar = Result.getAsSingle()) { Result.clear(); ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier())); return E; } goto Corrected; } } // We failed to correct; just fall through and let the parser deal with it. Result.suppressDiagnostics(); return NameClassification::Unknown(); case LookupResult::NotFoundInCurrentInstantiation: { // We performed name lookup into the current instantiation, and there were // dependent bases, so we treat this result the same way as any other // dependent nested-name-specifier. // C++ [temp.res]p2: // A name used in a template declaration or definition and that is // dependent on a template-parameter is assumed not to name a type // unless the applicable name lookup finds a type name or the name is // qualified by the keyword typename. // // FIXME: If the next token is '<', we might want to ask the parser to // perform some heroics to see if we actually have a // template-argument-list, which would indicate a missing 'template' // keyword here. return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, IsAddressOfOperand, /*TemplateArgs=*/nullptr); } case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: break; case LookupResult::Ambiguous: if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && hasAnyAcceptableTemplateNames(Result)) { // C++ [temp.local]p3: // A lookup that finds an injected-class-name (10.2) can result in an // ambiguity in certain cases (for example, if it is found in more than // one base class). If all of the injected-class-names that are found // refer to specializations of the same class template, and if the name // is followed by a template-argument-list, the reference refers to the // class template itself and not a specialization thereof, and is not // ambiguous. // // This filtering can make an ambiguous result into an unambiguous one, // so try again after filtering out template names. FilterAcceptableTemplateNames(Result); if (!Result.isAmbiguous()) { IsFilteredTemplateName = true; break; } } // Diagnose the ambiguity and return an error. return NameClassification::Error(); } if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) { // C++ [temp.names]p3: // After name lookup (3.4) finds that a name is a template-name or that // an operator-function-id or a literal- operator-id refers to a set of // overloaded functions any member of which is a function template if // this is followed by a <, the < is always taken as the delimiter of a // template-argument-list and never as the less-than operator. if (!IsFilteredTemplateName) FilterAcceptableTemplateNames(Result); if (!Result.empty()) { bool IsFunctionTemplate; bool IsVarTemplate; TemplateName Template; if (Result.end() - Result.begin() > 1) { IsFunctionTemplate = true; Template = Context.getOverloadedTemplateName(Result.begin(), Result.end()); } else { TemplateDecl *TD = cast((*Result.begin())->getUnderlyingDecl()); IsFunctionTemplate = isa(TD); IsVarTemplate = isa(TD); if (SS.isSet() && !SS.isInvalid()) Template = Context.getQualifiedTemplateName(SS.getScopeRep(), /*TemplateKeyword=*/false, TD); else Template = TemplateName(TD); } if (IsFunctionTemplate) { // Function templates always go through overload resolution, at which // point we'll perform the various checks (e.g., accessibility) we need // to based on which function we selected. Result.suppressDiagnostics(); return NameClassification::FunctionTemplate(Template); } return IsVarTemplate ? NameClassification::VarTemplate(Template) : NameClassification::TypeTemplate(Template); } } NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); if (TypeDecl *Type = dyn_cast(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); QualType T = Context.getTypeDeclType(Type); if (SS.isNotEmpty()) return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } ObjCInterfaceDecl *Class = dyn_cast(FirstDecl); if (!Class) { // FIXME: It's unfortunate that we don't have a Type node for handling this. if (ObjCCompatibleAliasDecl *Alias = dyn_cast(FirstDecl)) Class = Alias->getClassInterface(); } if (Class) { DiagnoseUseOfDecl(Class, NameLoc); if (NextToken.is(tok::period)) { // Interface. is parsed as a property reference expression. // Just return "unknown" as a fall-through for now. Result.suppressDiagnostics(); return NameClassification::Unknown(); } QualType T = Context.getObjCInterfaceType(Class); return ParsedType::make(T); } // We can have a type template here if we're classifying a template argument. if (isa(FirstDecl) && !isa(FirstDecl) && !isa(FirstDecl)) return NameClassification::TypeTemplate( TemplateName(cast(FirstDecl))); // Check for a tag type hidden by a non-type decl in a few cases where it // seems likely a type is wanted instead of the non-type that was found. bool NextIsOp = NextToken.isOneOf(tok::amp, tok::star); if ((NextToken.is(tok::identifier) || (NextIsOp && FirstDecl->getUnderlyingDecl()->isFunctionOrFunctionTemplate())) && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { TypeDecl *Type = Result.getAsSingle(); DiagnoseUseOfDecl(Type, NameLoc); QualType T = Context.getTypeDeclType(Type); if (SS.isNotEmpty()) return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } if (FirstDecl->isCXXClassMember()) return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr, S); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); return BuildDeclarationNameExpr(SS, Result, ADL); } Sema::TemplateNameKindForDiagnostics Sema::getTemplateNameKindForDiagnostics(TemplateName Name) { auto *TD = Name.getAsTemplateDecl(); if (!TD) return TemplateNameKindForDiagnostics::DependentTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::ClassTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::FunctionTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::VarTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::AliasTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::TemplateTemplateParam; return TemplateNameKindForDiagnostics::DependentTemplate; } // Determines the context to return to after temporarily entering a // context. This depends in an unnecessarily complicated way on the // exact ordering of callbacks from the parser. DeclContext *Sema::getContainingDC(DeclContext *DC) { // Functions defined inline within classes aren't parsed until we've // finished parsing the top-level class, so the top-level class is // the context we'll need to return to. // A Lambda call operator whose parent is a class must not be treated // as an inline member function. A Lambda can be used legally // either as an in-class member initializer or a default argument. These // are parsed once the class has been marked complete and so the containing // context would be the nested class (when the lambda is defined in one); // If the class is not complete, then the lambda is being used in an // ill-formed fashion (such as to specify the width of a bit-field, or // in an array-bound) - in which case we still want to return the // lexically containing DC (which could be a nested class). if (isa(DC) && !isLambdaCallOperator(DC)) { DC = DC->getLexicalParent(); // A function not defined within a class will always return to its // lexical context. if (!isa(DC)) return DC; // A C++ inline method/friend is parsed *after* the topmost class // it was declared in is fully parsed ("complete"); the topmost // class is the context we need to return to. while (CXXRecordDecl *RD = dyn_cast(DC->getLexicalParent())) DC = RD; // Return the declaration context of the topmost class the inline method is // declared in. return DC; } return DC->getLexicalParent(); } void Sema::PushDeclContext(Scope *S, DeclContext *DC) { assert(getContainingDC(DC) == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = DC; S->setEntity(DC); } void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); CurContext = getContainingDC(CurContext); assert(CurContext && "Popped translation unit!"); } Sema::SkippedDefinitionContext Sema::ActOnTagStartSkippedDefinition(Scope *S, Decl *D) { // Unlike PushDeclContext, the context to which we return is not necessarily // the containing DC of TD, because the new context will be some pre-existing // TagDecl definition instead of a fresh one. auto Result = static_cast(CurContext); CurContext = cast(D)->getDefinition(); assert(CurContext && "skipping definition of undefined tag"); // Start lookups from the parent of the current context; we don't want to look // into the pre-existing complete definition. S->setEntity(CurContext->getLookupParent()); return Result; } void Sema::ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context) { CurContext = static_cast(Context); } /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. /// void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) { // C++0x [basic.lookup.unqual]p13: // A name used in the definition of a static data member of class // X (after the qualified-id of the static member) is looked up as // if the name was used in a member function of X. // C++0x [basic.lookup.unqual]p14: // If a variable member of a namespace is defined outside of the // scope of its namespace then any name used in the definition of // the variable member (after the declarator-id) is looked up as // if the definition of the variable member occurred in its // namespace. // Both of these imply that we should push a scope whose context // is the semantic context of the declaration. We can't use // PushDeclContext here because that context is not necessarily // lexically contained in the current context. Fortunately, // the containing scope should have the appropriate information. assert(!S->getEntity() && "scope already has entity"); #ifndef NDEBUG Scope *Ancestor = S->getParent(); while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent(); assert(Ancestor->getEntity() == CurContext && "ancestor context mismatch"); #endif CurContext = DC; S->setEntity(DC); } void Sema::ExitDeclaratorContext(Scope *S) { assert(S->getEntity() == CurContext && "Context imbalance!"); // Switch back to the lexical context. The safety of this is // enforced by an assert in EnterDeclaratorContext. Scope *Ancestor = S->getParent(); while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent(); CurContext = Ancestor->getEntity(); // We don't need to do anything with the scope, which is going to // disappear. } void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { // We assume that the caller has already called // ActOnReenterTemplateScope so getTemplatedDecl() works. FunctionDecl *FD = D->getAsFunction(); if (!FD) return; // Same implementation as PushDeclContext, but enters the context // from the lexical parent, rather than the top-level class. assert(CurContext == FD->getLexicalParent() && "The next DeclContext should be lexically contained in the current one."); CurContext = FD; S->setEntity(CurContext); for (unsigned P = 0, NumParams = FD->getNumParams(); P < NumParams; ++P) { ParmVarDecl *Param = FD->getParamDecl(P); // If the parameter has an identifier, then add it to the scope if (Param->getIdentifier()) { S->AddDecl(Param); IdResolver.AddDecl(Param); } } } void Sema::ActOnExitFunctionContext() { // Same implementation as PopDeclContext, but returns to the lexical parent, // rather than the top-level class. assert(CurContext && "DeclContext imbalance!"); CurContext = CurContext->getLexicalParent(); assert(CurContext && "Popped translation unit!"); } /// \brief Determine whether we allow overloading of the function /// PrevDecl with another declaration. /// /// This routine determines whether overloading is possible, not /// whether some new function is actually an overload. It will return /// true in C++ (where we can always provide overloads) or, as an /// extension, in C when the previous function is already an /// overloaded function declaration or has the "overloadable" /// attribute. static bool AllowOverloadingOfFunction(LookupResult &Previous, ASTContext &Context) { if (Context.getLangOpts().CPlusPlus) return true; if (Previous.getResultKind() == LookupResult::FoundOverloaded) return true; return (Previous.getResultKind() == LookupResult::Found && Previous.getFoundDecl()->hasAttr()); } /// Add this decl to the scope shadowed decl chains. void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // Move up the scope chain until we find the nearest enclosing // non-transparent context. The declaration will be introduced into this // scope. while (S->getEntity() && S->getEntity()->isTransparentContext()) S = S->getParent(); // Add scoped declarations into their context, so that they can be // found later. Declarations without a context won't be inserted // into any context. if (AddToContext) CurContext->addDecl(D); // Out-of-line definitions shouldn't be pushed into scope in C++, unless they // are function-local declarations. if (getLangOpts().CPlusPlus && D->isOutOfLine() && !D->getDeclContext()->getRedeclContext()->Equals( D->getLexicalDeclContext()->getRedeclContext()) && !D->getLexicalDeclContext()->isFunctionOrMethod()) return; // Template instantiations should also not be pushed into scope. if (isa(D) && cast(D)->isFunctionTemplateSpecialization()) return; // If this replaces anything in the current scope, IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end(); for (; I != IEnd; ++I) { if (S->isDeclScope(*I) && D->declarationReplaces(*I)) { S->RemoveDecl(*I); IdResolver.RemoveDecl(*I); // Should only need to replace one decl. break; } } S->AddDecl(D); if (isa(D) && !cast(D)->isGnuLocal()) { // Implicitly-generated labels may end up getting generated in an order that // isn't strictly lexical, which breaks name lookup. Be careful to insert // the label at the appropriate place in the identifier chain. for (I = IdResolver.begin(D->getDeclName()); I != IEnd; ++I) { DeclContext *IDC = (*I)->getLexicalDeclContext()->getRedeclContext(); if (IDC == CurContext) { if (!S->isDeclScope(*I)) continue; } else if (IDC->Encloses(CurContext)) break; } IdResolver.InsertDeclAfter(I, D); } else { IdResolver.AddDecl(D); } } void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { if (IdResolver.tryAddTopLevelDecl(D, Name) && TUScope) TUScope->AddDecl(D); } bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S, bool AllowInlineNamespace) { return IdResolver.isDeclInScope(D, Ctx, S, AllowInlineNamespace); } Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) { DeclContext *TargetDC = DC->getPrimaryContext(); do { if (DeclContext *ScopeDC = S->getEntity()) if (ScopeDC->getPrimaryContext() == TargetDC) return S; } while ((S = S->getParent())); return nullptr; } static bool isOutOfScopePreviousDeclaration(NamedDecl *, DeclContext*, ASTContext&); /// Filters out lookup results that don't fall within the given scope /// as determined by isDeclInScope. void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (isDeclInScope(D, Ctx, S, AllowInlineNamespace)) continue; if (ConsiderLinkage && isOutOfScopePreviousDeclaration(D, Ctx, Context)) continue; F.erase(); } F.done(); } static bool isUsingDecl(NamedDecl *D) { return isa(D) || isa(D) || isa(D); } /// Removes using shadow declarations from the lookup results. static void RemoveUsingDecls(LookupResult &R) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) if (isUsingDecl(F.next())) F.erase(); F.done(); } /// \brief Check for this common pattern: /// @code /// class S { /// S(const S&); // DO NOT IMPLEMENT /// void operator=(const S&); // DO NOT IMPLEMENT /// }; /// @endcode static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { // FIXME: Should check for private access too but access is set after we get // the decl here. if (D->doesThisDeclarationHaveABody()) return false; if (const CXXConstructorDecl *CD = dyn_cast(D)) return CD->isCopyConstructor(); if (const CXXMethodDecl *Method = dyn_cast(D)) return Method->isCopyAssignmentOperator(); return false; } // We need this to handle // // typedef struct { // void *foo() { return 0; } // } A; // // When we see foo we don't know if after the typedef we will get 'A' or '*A' // for example. If 'A', foo will have external linkage. If we have '*A', // foo will have no linkage. Since we can't know until we get to the end // of the typedef, this function finds out if D might have non-external linkage. // Callers should verify at the end of the TU if it D has external linkage or // not. bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) { const DeclContext *DC = D->getDeclContext(); while (!DC->isTranslationUnit()) { if (const RecordDecl *RD = dyn_cast(DC)){ if (!RD->hasNameForLinkage()) return true; } DC = DC->getParent(); } return !D->isExternallyVisible(); } // FIXME: This needs to be refactored; some other isInMainFile users want // these semantics. static bool isMainFileLoc(const Sema &S, SourceLocation Loc) { if (S.TUKind != TU_Complete) return false; return S.SourceMgr.isInMainFile(Loc); } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { assert(D); if (D->isInvalidDecl() || D->isUsed() || D->hasAttr()) return false; // Ignore all entities declared within templates, and out-of-line definitions // of members of class templates. if (D->getDeclContext()->isDependentContext() || D->getLexicalDeclContext()->isDependentContext()) return false; if (const FunctionDecl *FD = dyn_cast(D)) { if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; // A non-out-of-line declaration of a member specialization was implicitly // instantiated; it's the out-of-line declaration that we're interested in. if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && FD->getMemberSpecializationInfo() && !FD->isOutOfLine()) return false; if (const CXXMethodDecl *MD = dyn_cast(FD)) { if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD)) return false; } else { // 'static inline' functions are defined in headers; don't warn. if (FD->isInlined() && !isMainFileLoc(*this, FD->getLocation())) return false; } if (FD->doesThisDeclarationHaveABody() && Context.DeclMustBeEmitted(FD)) return false; } else if (const VarDecl *VD = dyn_cast(D)) { // Constants and utility variables are defined in headers with internal // linkage; don't warn. (Unlike functions, there isn't a convenient marker // like "inline".) if (!isMainFileLoc(*this, VD->getLocation())) return false; if (Context.DeclMustBeEmitted(VD)) return false; if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && VD->getMemberSpecializationInfo() && !VD->isOutOfLine()) return false; if (VD->isInline() && !isMainFileLoc(*this, VD->getLocation())) return false; } else { return false; } // Only warn for unused decls internal to the translation unit. // FIXME: This seems like a bogus check; it suppresses -Wunused-function // for inline functions defined in the main source file, for instance. return mightHaveNonExternalLinkage(D); } void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { if (!D) return; if (const FunctionDecl *FD = dyn_cast(D)) { const FunctionDecl *First = FD->getFirstDecl(); if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First)) return; // First should already be in the vector. } if (const VarDecl *VD = dyn_cast(D)) { const VarDecl *First = VD->getFirstDecl(); if (VD != First && ShouldWarnIfUnusedFileScopedDecl(First)) return; // First should already be in the vector. } if (ShouldWarnIfUnusedFileScopedDecl(D)) UnusedFileScopedDecls.push_back(D); } static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isInvalidDecl()) return false; if (D->isReferenced() || D->isUsed() || D->hasAttr() || D->hasAttr()) return false; if (isa(D)) return true; // Except for labels, we only care about unused decls that are local to // functions. bool WithinFunction = D->getDeclContext()->isFunctionOrMethod(); if (const auto *R = dyn_cast(D->getDeclContext())) // For dependent types, the diagnostic is deferred. WithinFunction = WithinFunction || (R->isLocalClass() && !R->isDependentType()); if (!WithinFunction) return false; if (isa(D)) return true; // White-list anything that isn't a local variable. if (!isa(D) || isa(D) || isa(D)) return false; // Types of valid local variables should be complete, so this should succeed. if (const VarDecl *VD = dyn_cast(D)) { // White-list anything with an __attribute__((unused)) type. const auto *Ty = VD->getType().getTypePtr(); // Only look at the outermost level of typedef. if (const TypedefType *TT = Ty->getAs()) { if (TT->getDecl()->hasAttr()) return false; } // If we failed to complete the type for some reason, or if the type is // dependent, don't diagnose the variable. if (Ty->isIncompleteType() || Ty->isDependentType()) return false; // Look at the element type to ensure that the warning behaviour is // consistent for both scalars and arrays. Ty = Ty->getBaseElementTypeUnsafe(); if (const TagType *TT = Ty->getAs()) { const TagDecl *Tag = TT->getDecl(); if (Tag->hasAttr()) return false; if (const CXXRecordDecl *RD = dyn_cast(Tag)) { if (!RD->hasTrivialDestructor() && !RD->hasAttr()) return false; if (const Expr *Init = VD->getInit()) { if (const ExprWithCleanups *Cleanups = dyn_cast(Init)) Init = Cleanups->getSubExpr(); const CXXConstructExpr *Construct = dyn_cast(Init); if (Construct && !Construct->isElidable()) { CXXConstructorDecl *CD = Construct->getConstructor(); if (!CD->isTrivial() && !RD->hasAttr()) return false; } } } } // TODO: __attribute__((unused)) templates? } return true; } static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx, FixItHint &Hint) { if (isa(D)) { SourceLocation AfterColon = Lexer::findLocationAfterToken(D->getLocEnd(), tok::colon, Ctx.getSourceManager(), Ctx.getLangOpts(), true); if (AfterColon.isInvalid()) return; Hint = FixItHint::CreateRemoval(CharSourceRange:: getCharRange(D->getLocStart(), AfterColon)); } } void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) { if (D->getTypeForDecl()->isDependentType()) return; for (auto *TmpD : D->decls()) { if (const auto *T = dyn_cast(TmpD)) DiagnoseUnusedDecl(T); else if(const auto *R = dyn_cast(TmpD)) DiagnoseUnusedNestedTypedefs(R); } } /// DiagnoseUnusedDecl - Emit warnings about declarations that are not used /// unless they are marked attr(unused). void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { if (!ShouldDiagnoseUnusedDecl(D)) return; if (auto *TD = dyn_cast(D)) { // typedefs can be referenced later on, so the diagnostics are emitted // at end-of-translation-unit. UnusedLocalTypedefNameCandidates.insert(TD); return; } FixItHint Hint; GenerateFixForUnusedDecl(D, Context, Hint); unsigned DiagID; if (isa(D) && cast(D)->isExceptionVariable()) DiagID = diag::warn_unused_exception_param; else if (isa(D)) DiagID = diag::warn_unused_label; else DiagID = diag::warn_unused_variable; Diag(D->getLocation(), DiagID) << D->getDeclName() << Hint; } static void CheckPoppedLabel(LabelDecl *L, Sema &S) { // Verify that we have no forward references left. If so, there was a goto // or address of a label taken, but no definition of it. Label fwd // definitions are indicated with a null substmt which is also not a resolved // MS inline assembly label name. bool Diagnose = false; if (L->isMSAsmLabel()) Diagnose = !L->isResolvedMSAsmLabel(); else Diagnose = L->getStmt() == nullptr; if (Diagnose) S.Diag(L->getLocation(), diag::err_undeclared_label_use) <getDeclName(); } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { S->mergeNRVOIntoParent(); if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && "Scope shouldn't contain decls!"); for (auto *TmpD : S->decls()) { assert(TmpD && "This decl didn't get pushed??"); assert(isa(TmpD) && "Decl isn't NamedDecl?"); NamedDecl *D = cast(TmpD); if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. if (!S->hasUnrecoverableErrorOccurred()) { DiagnoseUnusedDecl(D); if (const auto *RD = dyn_cast(D)) DiagnoseUnusedNestedTypedefs(RD); } // If this was a forward reference to a label, verify it was defined. if (LabelDecl *LD = dyn_cast(D)) CheckPoppedLabel(LD, *this); // Remove this name from our lexical scope, and warn on it if we haven't // already. IdResolver.RemoveDecl(D); auto ShadowI = ShadowingDecls.find(D); if (ShadowI != ShadowingDecls.end()) { if (const auto *FD = dyn_cast(ShadowI->second)) { Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field) << D << FD << FD->getParent(); Diag(FD->getLocation(), diag::note_previous_declaration); } ShadowingDecls.erase(ShadowI); } } } /// \brief Look for an Objective-C class in the translation unit. /// /// \param Id The name of the Objective-C class we're looking for. If /// typo-correction fixes this name, the Id will be updated /// to the fixed name. /// /// \param IdLoc The location of the name in the translation unit. /// /// \param DoTypoCorrection If true, this routine will attempt typo correction /// if there is no class with the given name. /// /// \returns The declaration of the named Objective-C class, or NULL if the /// class could not be found. ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, bool DoTypoCorrection) { // The third "scope" argument is 0 since we aren't enabling lazy built-in // creation from this context. NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName); if (!IDecl && DoTypoCorrection) { // Perform typo correction at the given location, but only if we // find an Objective-C class name. if (TypoCorrection C = CorrectTypo( DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, TUScope, nullptr, llvm::make_unique>(), CTK_ErrorRecovery)) { diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id); IDecl = C.getCorrectionDeclAs(); Id = IDecl->getIdentifier(); } } ObjCInterfaceDecl *Def = dyn_cast_or_null(IDecl); // This routine must always return a class definition, if any. if (Def && Def->getDefinition()) Def = Def->getDefinition(); return Def; } /// getNonFieldDeclScope - Retrieves the innermost scope, starting /// from S, where a non-field would be declared. This routine copes /// with the difference between C and C++ scoping rules in structs and /// unions. For example, the following code is well-formed in C but /// ill-formed in C++: /// @code /// struct S6 { /// enum { BAR } e; /// }; /// /// void test_S6() { /// struct S6 a; /// a.e = BAR; /// } /// @endcode /// For the declaration of BAR, this routine will return a different /// scope. The scope S will be the scope of the unnamed enumeration /// within S6. In C++, this routine will return the scope associated /// with S6, because the enumeration's scope is a transparent /// context but structures can contain non-field names. In C, this /// routine will return the translation unit scope, since the /// enumeration's scope is a transparent context and structures cannot /// contain non-field names. Scope *Sema::getNonFieldDeclScope(Scope *S) { while (((S->getFlags() & Scope::DeclScope) == 0) || (S->getEntity() && S->getEntity()->isTransparentContext()) || (S->isClassScope() && !getLangOpts().CPlusPlus)) S = S->getParent(); return S; } /// \brief Looks up the declaration of "struct objc_super" and /// saves it for later use in building builtin declaration of /// objc_msgSendSuper and objc_msgSendSuper_stret. If no such /// pre-existing declaration exists no action takes place. static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S, IdentifierInfo *II) { if (!II->isStr("objc_msgSendSuper")) return; ASTContext &Context = ThisSema.Context; LookupResult Result(ThisSema, &Context.Idents.get("objc_super"), SourceLocation(), Sema::LookupTagName); ThisSema.LookupName(Result, S); if (Result.getResultKind() == LookupResult::Found) if (const TagDecl *TD = Result.getAsSingle()) Context.setObjCSuperType(Context.getTagDeclType(TD)); } static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) { switch (Error) { case ASTContext::GE_None: return ""; case ASTContext::GE_Missing_stdio: return "stdio.h"; case ASTContext::GE_Missing_setjmp: return "setjmp.h"; case ASTContext::GE_Missing_ucontext: return "ucontext.h"; } llvm_unreachable("unhandled error kind"); } /// LazilyCreateBuiltin - The specified Builtin-ID was first used at /// file scope. lazily create a decl for it. ForRedeclaration is true /// if we're creating this built-in in anticipation of redeclaring the /// built-in. NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc) { LookupPredefedObjCSuperType(*this, S, II); ASTContext::GetBuiltinTypeError Error; QualType R = Context.GetBuiltinType(ID, Error); if (Error) { if (ForRedeclaration) Diag(Loc, diag::warn_implicit_decl_requires_sysheader) << getHeaderName(Error) << Context.BuiltinInfo.getName(ID); return nullptr; } if (!ForRedeclaration && (Context.BuiltinInfo.isPredefinedLibFunction(ID) || Context.BuiltinInfo.isHeaderDependentFunction(ID))) { Diag(Loc, diag::ext_implicit_lib_function_decl) << Context.BuiltinInfo.getName(ID) << R; if (Context.BuiltinInfo.getHeaderName(ID) && !Diags.isIgnored(diag::ext_implicit_lib_function_decl, Loc)) Diag(Loc, diag::note_include_header_or_declare) << Context.BuiltinInfo.getHeaderName(ID) << Context.BuiltinInfo.getName(ID); } if (R.isNull()) return nullptr; DeclContext *Parent = Context.getTranslationUnitDecl(); if (getLangOpts().CPlusPlus) { LinkageSpecDecl *CLinkageDecl = LinkageSpecDecl::Create(Context, Parent, Loc, Loc, LinkageSpecDecl::lang_c, false); CLinkageDecl->setImplicit(); Parent->addDecl(CLinkageDecl); Parent = CLinkageDecl; } FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, R, /*TInfo=*/nullptr, SC_Extern, false, R->isFunctionProtoType()); New->setImplicit(); // Create Decl objects for each parameter, adding them to the // FunctionDecl. if (const FunctionProtoType *FT = dyn_cast(R)) { SmallVector Params; for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { ParmVarDecl *parm = ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(), nullptr, FT->getParamType(i), /*TInfo=*/nullptr, SC_None, nullptr); parm->setScopeInfo(0, i); Params.push_back(parm); } New->setParams(Params); } AddKnownFunctionAttributes(New); RegisterLocallyScopedExternCDecl(New, S); // TUScope is the translation-unit scope to insert this function into. // FIXME: This is hideous. We need to teach PushOnScopeChains to // relate Scopes to DeclContexts, and probably eliminate CurContext // entirely, but we're not there yet. DeclContext *SavedContext = CurContext; CurContext = Parent; PushOnScopeChains(New, TUScope); CurContext = SavedContext; return New; } /// Typedef declarations don't have linkage, but they still denote the same /// entity if their types are the same. /// FIXME: This is notionally doing the same thing as ASTReaderDecl's /// isSameEntity. static void filterNonConflictingPreviousTypedefDecls(Sema &S, TypedefNameDecl *Decl, LookupResult &Previous) { // This is only interesting when modules are enabled. if (!S.getLangOpts().Modules && !S.getLangOpts().ModulesLocalVisibility) return; // Empty sets are uninteresting. if (Previous.empty()) return; LookupResult::Filter Filter = Previous.makeFilter(); while (Filter.hasNext()) { NamedDecl *Old = Filter.next(); // Non-hidden declarations are never ignored. if (S.isVisible(Old)) continue; // Declarations of the same entity are not ignored, even if they have // different linkages. if (auto *OldTD = dyn_cast(Old)) { if (S.Context.hasSameType(OldTD->getUnderlyingType(), Decl->getUnderlyingType())) continue; // If both declarations give a tag declaration a typedef name for linkage // purposes, then they declare the same entity. if (S.getLangOpts().CPlusPlus && OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) && Decl->getAnonDeclWithTypedefName()) continue; } Filter.erase(); } Filter.done(); } bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { QualType OldType; if (TypedefNameDecl *OldTypedef = dyn_cast(Old)) OldType = OldTypedef->getUnderlyingType(); else OldType = Context.getTypeDeclType(Old); QualType NewType = New->getUnderlyingType(); if (NewType->isVariablyModifiedType()) { // Must not redefine a typedef with a variably-modified type. int Kind = isa(Old) ? 1 : 0; Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef) << Kind << NewType; if (Old->getLocation().isValid()) notePreviousDefinition(Old->getLocation(), New->getLocation()); New->setInvalidDecl(); return true; } if (OldType != NewType && !OldType->isDependentType() && !NewType->isDependentType() && !Context.hasSameType(OldType, NewType)) { int Kind = isa(Old) ? 1 : 0; Diag(New->getLocation(), diag::err_redefinition_different_typedef) << Kind << NewType << OldType; if (Old->getLocation().isValid()) notePreviousDefinition(Old->getLocation(), New->getLocation()); New->setInvalidDecl(); return true; } return false; } /// MergeTypedefNameDecl - We just parsed a typedef 'New' which has the /// same name and scope as a previous declaration 'Old'. Figure out /// how to resolve this situation, merging decls or emitting /// diagnostics as appropriate. If there was an error, set New to be invalid. /// void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, LookupResult &OldDecls) { // If the new decl is known invalid already, don't bother doing any // merging checks. if (New->isInvalidDecl()) return; // Allow multiple definitions for ObjC built-in typedefs. // FIXME: Verify the underlying types are equivalent! if (getLangOpts().ObjC1) { const IdentifierInfo *TypeID = New->getIdentifier(); switch (TypeID->getLength()) { default: break; case 2: { if (!TypeID->isStr("id")) break; QualType T = New->getUnderlyingType(); if (!T->isPointerType()) break; if (!T->isVoidPointerType()) { QualType PT = T->getAs()->getPointeeType(); if (!PT->isStructureType()) break; } Context.setObjCIdRedefinitionType(T); // Install the built-in type for 'id', ignoring the current definition. New->setTypeForDecl(Context.getObjCIdType().getTypePtr()); return; } case 5: if (!TypeID->isStr("Class")) break; Context.setObjCClassRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'Class', ignoring the current definition. New->setTypeForDecl(Context.getObjCClassType().getTypePtr()); return; case 3: if (!TypeID->isStr("SEL")) break; Context.setObjCSelRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'SEL', ignoring the current definition. New->setTypeForDecl(Context.getObjCSelType().getTypePtr()); return; } // Fall through - the typedef name was not a builtin type. } // Verify the old decl was also a type. TypeDecl *Old = OldDecls.getAsSingle(); if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); NamedDecl *OldD = OldDecls.getRepresentativeDecl(); if (OldD->getLocation().isValid()) notePreviousDefinition(OldD->getLocation(), New->getLocation()); return New->setInvalidDecl(); } // If the old declaration is invalid, just give up here. if (Old->isInvalidDecl()) return New->setInvalidDecl(); if (auto *OldTD = dyn_cast(Old)) { auto *OldTag = OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true); auto *NewTag = New->getAnonDeclWithTypedefName(); NamedDecl *Hidden = nullptr; if (getLangOpts().CPlusPlus && OldTag && NewTag && OldTag->getCanonicalDecl() != NewTag->getCanonicalDecl() && !hasVisibleDefinition(OldTag, &Hidden)) { // There is a definition of this tag, but it is not visible. Use it // instead of our tag. New->setTypeForDecl(OldTD->getTypeForDecl()); if (OldTD->isModed()) New->setModedTypeSourceInfo(OldTD->getTypeSourceInfo(), OldTD->getUnderlyingType()); else New->setTypeSourceInfo(OldTD->getTypeSourceInfo()); // Make the old tag definition visible. makeMergedDefinitionVisible(Hidden); // If this was an unscoped enumeration, yank all of its enumerators // out of the scope. if (isa(NewTag)) { Scope *EnumScope = getNonFieldDeclScope(S); for (auto *D : NewTag->decls()) { auto *ED = cast(D); assert(EnumScope->isDeclScope(ED)); EnumScope->RemoveDecl(ED); IdResolver.RemoveDecl(ED); ED->getLexicalDeclContext()->removeDecl(ED); } } } } // If the typedef types are not identical, reject them in all languages and // with any extensions enabled. if (isIncompatibleTypedef(Old, New)) return; // The types match. Link up the redeclaration chain and merge attributes if // the old declaration was a typedef. if (TypedefNameDecl *Typedef = dyn_cast(Old)) { New->setPreviousDecl(Typedef); mergeDeclAttributes(New, Old); } if (getLangOpts().MicrosoftExt) return; if (getLangOpts().CPlusPlus) { // C++ [dcl.typedef]p2: // In a given non-class scope, a typedef specifier can be used to // redefine the name of any type declared in that scope to refer // to the type to which it already refers. if (!isa(CurContext)) return; // C++0x [dcl.typedef]p4: // In a given class scope, a typedef specifier can be used to redefine // any class-name declared in that scope that is not also a typedef-name // to refer to the type to which it already refers. // // This wording came in via DR424, which was a correction to the // wording in DR56, which accidentally banned code like: // // struct S { // typedef struct A { } A; // }; // // in the C++03 standard. We implement the C++0x semantics, which // allow the above but disallow // // struct S { // typedef int I; // typedef int I; // }; // // since that was the intent of DR56. if (!isa(Old)) return; Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); notePreviousDefinition(Old->getLocation(), New->getLocation()); return New->setInvalidDecl(); } // Modules always permit redefinition of typedefs, as does C11. if (getLangOpts().Modules || getLangOpts().C11) return; // If we have a redefinition of a typedef in C, emit a warning. This warning // is normally mapped to an error, but can be controlled with // -Wtypedef-redefinition. If either the original or the redefinition is // in a system header, don't emit this for compatibility with GCC. if (getDiagnostics().getSuppressSystemWarnings() && // Some standard types are defined implicitly in Clang (e.g. OpenCL). (Old->isImplicit() || Context.getSourceManager().isInSystemHeader(Old->getLocation()) || Context.getSourceManager().isInSystemHeader(New->getLocation()))) return; Diag(New->getLocation(), diag::ext_redefinition_of_typedef) << New->getDeclName(); notePreviousDefinition(Old->getLocation(), New->getLocation()); } /// DeclhasAttr - returns true if decl Declaration already has the target /// attribute. static bool DeclHasAttr(const Decl *D, const Attr *A) { const OwnershipAttr *OA = dyn_cast(A); const AnnotateAttr *Ann = dyn_cast(A); for (const auto *i : D->attrs()) if (i->getKind() == A->getKind()) { if (Ann) { if (Ann->getAnnotation() == cast(i)->getAnnotation()) return true; continue; } // FIXME: Don't hardcode this check if (OA && isa(i)) return OA->getOwnKind() == cast(i)->getOwnKind(); return true; } return false; } static bool isAttributeTargetADefinition(Decl *D) { if (VarDecl *VD = dyn_cast(D)) return VD->isThisDeclarationADefinition(); if (TagDecl *TD = dyn_cast(D)) return TD->isCompleteDefinition() || TD->isBeingDefined(); return true; } /// Merge alignment attributes from \p Old to \p New, taking into account the /// special semantics of C11's _Alignas specifier and C++11's alignas attribute. /// /// \return \c true if any attributes were added to \p New. static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) { // Look for alignas attributes on Old, and pick out whichever attribute // specifies the strictest alignment requirement. AlignedAttr *OldAlignasAttr = nullptr; AlignedAttr *OldStrictestAlignAttr = nullptr; unsigned OldAlign = 0; for (auto *I : Old->specific_attrs()) { // FIXME: We have no way of representing inherited dependent alignments // in a case like: // template struct alignas(A) X; // template struct alignas(B) X {}; // For now, we just ignore any alignas attributes which are not on the // definition in such a case. if (I->isAlignmentDependent()) return false; if (I->isAlignas()) OldAlignasAttr = I; unsigned Align = I->getAlignment(S.Context); if (Align > OldAlign) { OldAlign = Align; OldStrictestAlignAttr = I; } } // Look for alignas attributes on New. AlignedAttr *NewAlignasAttr = nullptr; unsigned NewAlign = 0; for (auto *I : New->specific_attrs()) { if (I->isAlignmentDependent()) return false; if (I->isAlignas()) NewAlignasAttr = I; unsigned Align = I->getAlignment(S.Context); if (Align > NewAlign) NewAlign = Align; } if (OldAlignasAttr && NewAlignasAttr && OldAlign != NewAlign) { // Both declarations have 'alignas' attributes. We require them to match. // C++11 [dcl.align]p6 and C11 6.7.5/7 both come close to saying this, but // fall short. (If two declarations both have alignas, they must both match // every definition, and so must match each other if there is a definition.) // If either declaration only contains 'alignas(0)' specifiers, then it // specifies the natural alignment for the type. if (OldAlign == 0 || NewAlign == 0) { QualType Ty; if (ValueDecl *VD = dyn_cast(New)) Ty = VD->getType(); else Ty = S.Context.getTagDeclType(cast(New)); if (OldAlign == 0) OldAlign = S.Context.getTypeAlign(Ty); if (NewAlign == 0) NewAlign = S.Context.getTypeAlign(Ty); } if (OldAlign != NewAlign) { S.Diag(NewAlignasAttr->getLocation(), diag::err_alignas_mismatch) << (unsigned)S.Context.toCharUnitsFromBits(OldAlign).getQuantity() << (unsigned)S.Context.toCharUnitsFromBits(NewAlign).getQuantity(); S.Diag(OldAlignasAttr->getLocation(), diag::note_previous_declaration); } } if (OldAlignasAttr && !NewAlignasAttr && isAttributeTargetADefinition(New)) { // C++11 [dcl.align]p6: // if any declaration of an entity has an alignment-specifier, // every defining declaration of that entity shall specify an // equivalent alignment. // C11 6.7.5/7: // If the definition of an object does not have an alignment // specifier, any other declaration of that object shall also // have no alignment specifier. S.Diag(New->getLocation(), diag::err_alignas_missing_on_definition) << OldAlignasAttr; S.Diag(OldAlignasAttr->getLocation(), diag::note_alignas_on_declaration) << OldAlignasAttr; } bool AnyAdded = false; // Ensure we have an attribute representing the strictest alignment. if (OldAlign > NewAlign) { AlignedAttr *Clone = OldStrictestAlignAttr->clone(S.Context); Clone->setInherited(true); New->addAttr(Clone); AnyAdded = true; } // Ensure we have an alignas attribute if the old declaration had one. if (OldAlignasAttr && !NewAlignasAttr && !(AnyAdded && OldStrictestAlignAttr->isAlignas())) { AlignedAttr *Clone = OldAlignasAttr->clone(S.Context); Clone->setInherited(true); New->addAttr(Clone); AnyAdded = true; } return AnyAdded; } static bool mergeDeclAttribute(Sema &S, NamedDecl *D, const InheritableAttr *Attr, Sema::AvailabilityMergeKind AMK) { // This function copies an attribute Attr from a previous declaration to the // new declaration D if the new declaration doesn't itself have that attribute // yet or if that attribute allows duplicates. // If you're adding a new attribute that requires logic different from // "use explicit attribute on decl if present, else use attribute from // previous decl", for example if the attribute needs to be consistent // between redeclarations, you need to call a custom merge function here. InheritableAttr *NewAttr = nullptr; unsigned AttrSpellingListIndex = Attr->getSpellingListIndex(); if (const auto *AA = dyn_cast(Attr)) NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(), AA->isImplicit(), AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(), AA->getUnavailable(), AA->getMessage(), AA->getStrict(), AA->getReplacement(), AMK, AttrSpellingListIndex); else if (const auto *VA = dyn_cast(Attr)) NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), AttrSpellingListIndex); else if (const auto *VA = dyn_cast(Attr)) NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), AttrSpellingListIndex); else if (const auto *ImportA = dyn_cast(Attr)) NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(), AttrSpellingListIndex); else if (const auto *ExportA = dyn_cast(Attr)) NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(), AttrSpellingListIndex); else if (const auto *FA = dyn_cast(Attr)) NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(), FA->getFormatIdx(), FA->getFirstArg(), AttrSpellingListIndex); else if (const auto *SA = dyn_cast(Attr)) NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(), AttrSpellingListIndex); else if (const auto *IA = dyn_cast(Attr)) NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(), AttrSpellingListIndex, IA->getSemanticSpelling()); else if (const auto *AA = dyn_cast(Attr)) NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(), &S.Context.Idents.get(AA->getSpelling()), AttrSpellingListIndex); else if (S.getLangOpts().CUDA && isa(D) && (isa(Attr) || isa(Attr) || isa(Attr))) { // CUDA target attributes are part of function signature for // overloading purposes and must not be merged. return false; } else if (const auto *MA = dyn_cast(Attr)) NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex); else if (const auto *OA = dyn_cast(Attr)) NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex); else if (const auto *InternalLinkageA = dyn_cast(Attr)) NewAttr = S.mergeInternalLinkageAttr( D, InternalLinkageA->getRange(), &S.Context.Idents.get(InternalLinkageA->getSpelling()), AttrSpellingListIndex); else if (const auto *CommonA = dyn_cast(Attr)) NewAttr = S.mergeCommonAttr(D, CommonA->getRange(), &S.Context.Idents.get(CommonA->getSpelling()), AttrSpellingListIndex); else if (isa(Attr)) // AlignedAttrs are handled separately, because we need to handle all // such attributes on a declaration at the same time. NewAttr = nullptr; else if ((isa(Attr) || isa(Attr)) && (AMK == Sema::AMK_Override || AMK == Sema::AMK_ProtocolImplementation)) NewAttr = nullptr; else if (const auto *UA = dyn_cast(Attr)) NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex, UA->getGuid()); else if (Attr->duplicatesAllowed() || !DeclHasAttr(D, Attr)) NewAttr = cast(Attr->clone(S.Context)); if (NewAttr) { NewAttr->setInherited(true); D->addAttr(NewAttr); if (isa(NewAttr)) S.Consumer.AssignInheritanceModel(cast(D)); return true; } return false; } static const Decl *getDefinition(const Decl *D) { if (const TagDecl *TD = dyn_cast(D)) return TD->getDefinition(); if (const VarDecl *VD = dyn_cast(D)) { const VarDecl *Def = VD->getDefinition(); if (Def) return Def; return VD->getActingDefinition(); } if (const FunctionDecl *FD = dyn_cast(D)) return FD->getDefinition(); return nullptr; } static bool hasAttribute(const Decl *D, attr::Kind Kind) { for (const auto *Attribute : D->attrs()) if (Attribute->getKind() == Kind) return true; return false; } /// checkNewAttributesAfterDef - If we already have a definition, check that /// there are no new attributes in this declaration. static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { if (!New->hasAttrs()) return; const Decl *Def = getDefinition(Old); if (!Def || Def == New) return; AttrVec &NewAttributes = New->getAttrs(); for (unsigned I = 0, E = NewAttributes.size(); I != E;) { const Attr *NewAttribute = NewAttributes[I]; if (isa(NewAttribute) || isa(NewAttribute)) { if (FunctionDecl *FD = dyn_cast(New)) { Sema::SkipBodyInfo SkipBody; S.CheckForFunctionRedefinition(FD, cast(Def), &SkipBody); // If we're skipping this definition, drop the "alias" attribute. if (SkipBody.ShouldSkip) { NewAttributes.erase(NewAttributes.begin() + I); --E; continue; } } else { VarDecl *VD = cast(New); unsigned Diag = cast(Def)->isThisDeclarationADefinition() == VarDecl::TentativeDefinition ? diag::err_alias_after_tentative : diag::err_redefinition; S.Diag(VD->getLocation(), Diag) << VD->getDeclName(); if (Diag == diag::err_redefinition) S.notePreviousDefinition(Def->getLocation(), VD->getLocation()); else S.Diag(Def->getLocation(), diag::note_previous_definition); VD->setInvalidDecl(); } ++I; continue; } if (const VarDecl *VD = dyn_cast(Def)) { // Tentative definitions are only interesting for the alias check above. if (VD->isThisDeclarationADefinition() != VarDecl::Definition) { ++I; continue; } } if (hasAttribute(Def, NewAttribute->getKind())) { ++I; continue; // regular attr merging will take care of validating this. } if (isa(NewAttribute)) { // C's _Noreturn is allowed to be added to a function after it is defined. ++I; continue; } else if (const AlignedAttr *AA = dyn_cast(NewAttribute)) { if (AA->isAlignas()) { // C++11 [dcl.align]p6: // if any declaration of an entity has an alignment-specifier, // every defining declaration of that entity shall specify an // equivalent alignment. // C11 6.7.5/7: // If the definition of an object does not have an alignment // specifier, any other declaration of that object shall also // have no alignment specifier. S.Diag(Def->getLocation(), diag::err_alignas_missing_on_definition) << AA; S.Diag(NewAttribute->getLocation(), diag::note_alignas_on_declaration) << AA; NewAttributes.erase(NewAttributes.begin() + I); --E; continue; } } S.Diag(NewAttribute->getLocation(), diag::warn_attribute_precede_definition); S.Diag(Def->getLocation(), diag::note_previous_definition); NewAttributes.erase(NewAttributes.begin() + I); --E; } } /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK) { if (UsedAttr *OldAttr = Old->getMostRecentDecl()->getAttr()) { UsedAttr *NewAttr = OldAttr->clone(Context); NewAttr->setInherited(true); New->addAttr(NewAttr); } if (!Old->hasAttrs() && !New->hasAttrs()) return; // Attributes declared post-definition are currently ignored. checkNewAttributesAfterDef(*this, New, Old); if (AsmLabelAttr *NewA = New->getAttr()) { if (AsmLabelAttr *OldA = Old->getAttr()) { if (OldA->getLabel() != NewA->getLabel()) { // This redeclaration changes __asm__ label. Diag(New->getLocation(), diag::err_different_asm_label); Diag(OldA->getLocation(), diag::note_previous_declaration); } } else if (Old->isUsed()) { // This redeclaration adds an __asm__ label to a declaration that has // already been ODR-used. Diag(New->getLocation(), diag::err_late_asm_label_name) << isa(Old) << New->getAttr()->getRange(); } } // Re-declaration cannot add abi_tag's. if (const auto *NewAbiTagAttr = New->getAttr()) { if (const auto *OldAbiTagAttr = Old->getAttr()) { for (const auto &NewTag : NewAbiTagAttr->tags()) { if (std::find(OldAbiTagAttr->tags_begin(), OldAbiTagAttr->tags_end(), NewTag) == OldAbiTagAttr->tags_end()) { Diag(NewAbiTagAttr->getLocation(), diag::err_new_abi_tag_on_redeclaration) << NewTag; Diag(OldAbiTagAttr->getLocation(), diag::note_previous_declaration); } } } else { Diag(NewAbiTagAttr->getLocation(), diag::err_abi_tag_on_redeclaration); Diag(Old->getLocation(), diag::note_previous_declaration); } } if (!Old->hasAttrs()) return; bool foundAny = New->hasAttrs(); // Ensure that any moving of objects within the allocated map is done before // we process them. if (!foundAny) New->setAttrs(AttrVec()); for (auto *I : Old->specific_attrs()) { // Ignore deprecated/unavailable/availability attributes if requested. AvailabilityMergeKind LocalAMK = AMK_None; if (isa(I) || isa(I) || isa(I)) { switch (AMK) { case AMK_None: continue; case AMK_Redeclaration: case AMK_Override: case AMK_ProtocolImplementation: LocalAMK = AMK; break; } } // Already handled. if (isa(I)) continue; if (mergeDeclAttribute(*this, New, I, LocalAMK)) foundAny = true; } if (mergeAlignedAttrs(*this, New, Old)) foundAny = true; if (!foundAny) New->dropAttrs(); } /// mergeParamDeclAttributes - Copy attributes from the old parameter /// to the new one. static void mergeParamDeclAttributes(ParmVarDecl *newDecl, const ParmVarDecl *oldDecl, Sema &S) { // C++11 [dcl.attr.depend]p2: // The first declaration of a function shall specify the // carries_dependency attribute for its declarator-id if any declaration // of the function specifies the carries_dependency attribute. const CarriesDependencyAttr *CDA = newDecl->getAttr(); if (CDA && !oldDecl->hasAttr()) { S.Diag(CDA->getLocation(), diag::err_carries_dependency_missing_on_first_decl) << 1/*Param*/; // Find the first declaration of the parameter. // FIXME: Should we build redeclaration chains for function parameters? const FunctionDecl *FirstFD = cast(oldDecl->getDeclContext())->getFirstDecl(); const ParmVarDecl *FirstVD = FirstFD->getParamDecl(oldDecl->getFunctionScopeIndex()); S.Diag(FirstVD->getLocation(), diag::note_carries_dependency_missing_first_decl) << 1/*Param*/; } if (!oldDecl->hasAttrs()) return; bool foundAny = newDecl->hasAttrs(); // Ensure that any moving of objects within the allocated map is // done before we process them. if (!foundAny) newDecl->setAttrs(AttrVec()); for (const auto *I : oldDecl->specific_attrs()) { if (!DeclHasAttr(newDecl, I)) { InheritableAttr *newAttr = cast(I->clone(S.Context)); newAttr->setInherited(true); newDecl->addAttr(newAttr); foundAny = true; } } if (!foundAny) newDecl->dropAttrs(); } static void mergeParamDeclTypes(ParmVarDecl *NewParam, const ParmVarDecl *OldParam, Sema &S) { if (auto Oldnullability = OldParam->getType()->getNullability(S.Context)) { if (auto Newnullability = NewParam->getType()->getNullability(S.Context)) { if (*Oldnullability != *Newnullability) { S.Diag(NewParam->getLocation(), diag::warn_mismatched_nullability_attr) << DiagNullabilityKind( *Newnullability, ((NewParam->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0)) << DiagNullabilityKind( *Oldnullability, ((OldParam->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0)); S.Diag(OldParam->getLocation(), diag::note_previous_declaration); } } else { QualType NewT = NewParam->getType(); NewT = S.Context.getAttributedType( AttributedType::getNullabilityAttrKind(*Oldnullability), NewT, NewT); NewParam->setType(NewT); } } } namespace { /// Used in MergeFunctionDecl to keep track of function parameters in /// C. struct GNUCompatibleParamWarning { ParmVarDecl *OldParm; ParmVarDecl *NewParm; QualType PromotedType; }; } // end anonymous namespace /// getSpecialMember - get the special member enum for a method. Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { if (const CXXConstructorDecl *Ctor = dyn_cast(MD)) { if (Ctor->isDefaultConstructor()) return Sema::CXXDefaultConstructor; if (Ctor->isCopyConstructor()) return Sema::CXXCopyConstructor; if (Ctor->isMoveConstructor()) return Sema::CXXMoveConstructor; } else if (isa(MD)) { return Sema::CXXDestructor; } else if (MD->isCopyAssignmentOperator()) { return Sema::CXXCopyAssignment; } else if (MD->isMoveAssignmentOperator()) { return Sema::CXXMoveAssignment; } return Sema::CXXInvalid; } // Determine whether the previous declaration was a definition, implicit // declaration, or a declaration. template static std::pair getNoteDiagForInvalidRedeclaration(const T *Old, const T *New) { diag::kind PrevDiag; SourceLocation OldLocation = Old->getLocation(); if (Old->isThisDeclarationADefinition()) PrevDiag = diag::note_previous_definition; else if (Old->isImplicit()) { PrevDiag = diag::note_previous_implicit_declaration; if (OldLocation.isInvalid()) OldLocation = New->getLocation(); } else PrevDiag = diag::note_previous_declaration; return std::make_pair(PrevDiag, OldLocation); } /// canRedefineFunction - checks if a function can be redefined. Currently, /// only extern inline functions can be redefined, and even then only in /// GNU89 mode. static bool canRedefineFunction(const FunctionDecl *FD, const LangOptions& LangOpts) { return ((FD->hasAttr() || LangOpts.GNUInline) && !LangOpts.CPlusPlus && FD->isInlineSpecified() && FD->getStorageClass() == SC_Extern); } const AttributedType *Sema::getCallingConvAttributedType(QualType T) const { const AttributedType *AT = T->getAs(); while (AT && !AT->isCallingConv()) AT = AT->getModifiedType()->getAs(); return AT; } template static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { const DeclContext *DC = Old->getDeclContext(); if (DC->isRecord()) return false; LanguageLinkage OldLinkage = Old->getLanguageLinkage(); if (OldLinkage == CXXLanguageLinkage && New->isInExternCContext()) return true; if (OldLinkage == CLanguageLinkage && New->isInExternCXXContext()) return true; return false; } template static bool isExternC(T *D) { return D->isExternC(); } static bool isExternC(VarTemplateDecl *) { return false; } /// \brief Check whether a redeclaration of an entity introduced by a /// using-declaration is valid, given that we know it's not an overload /// (nor a hidden tag declaration). template static bool checkUsingShadowRedecl(Sema &S, UsingShadowDecl *OldS, ExpectedDecl *New) { // C++11 [basic.scope.declarative]p4: // Given a set of declarations in a single declarative region, each of // which specifies the same unqualified name, // -- they shall all refer to the same entity, or all refer to functions // and function templates; or // -- exactly one declaration shall declare a class name or enumeration // name that is not a typedef name and the other declarations shall all // refer to the same variable or enumerator, or all refer to functions // and function templates; in this case the class name or enumeration // name is hidden (3.3.10). // C++11 [namespace.udecl]p14: // If a function declaration in namespace scope or block scope has the // same name and the same parameter-type-list as a function introduced // by a using-declaration, and the declarations do not declare the same // function, the program is ill-formed. auto *Old = dyn_cast(OldS->getTargetDecl()); if (Old && !Old->getDeclContext()->getRedeclContext()->Equals( New->getDeclContext()->getRedeclContext()) && !(isExternC(Old) && isExternC(New))) Old = nullptr; if (!Old) { S.Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); S.Diag(OldS->getTargetDecl()->getLocation(), diag::note_using_decl_target); S.Diag(OldS->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; return true; } return false; } static bool hasIdenticalPassObjectSizeAttrs(const FunctionDecl *A, const FunctionDecl *B) { assert(A->getNumParams() == B->getNumParams()); auto AttrEq = [](const ParmVarDecl *A, const ParmVarDecl *B) { const auto *AttrA = A->getAttr(); const auto *AttrB = B->getAttr(); if (AttrA == AttrB) return true; return AttrA && AttrB && AttrA->getType() == AttrB->getType(); }; return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq); } /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, /// merging decls or emitting diagnostics as appropriate. /// /// In C++, New and Old must be declarations that are not /// overloaded. Use IsOverload to determine whether New and Old are /// overloaded, and to select the Old declaration that New should be /// merged with. /// /// Returns true if there was an error, false otherwise. bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, bool MergeTypeWithOld) { // Verify the old decl was also a function. FunctionDecl *Old = OldD->getAsFunction(); if (!Old) { if (UsingShadowDecl *Shadow = dyn_cast(OldD)) { if (New->getFriendObjectKind()) { Diag(New->getLocation(), diag::err_using_decl_friend); Diag(Shadow->getTargetDecl()->getLocation(), diag::note_using_decl_target); Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; return true; } // Check whether the two declarations might declare the same function. if (checkUsingShadowRedecl(*this, Shadow, New)) return true; OldD = Old = cast(Shadow->getTargetDecl()); } else { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); notePreviousDefinition(OldD->getLocation(), New->getLocation()); return true; } } // If the old declaration is invalid, just give up here. if (Old->isInvalidDecl()) return true; diag::kind PrevDiag; SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = getNoteDiagForInvalidRedeclaration(Old, New); // Don't complain about this if we're in GNU89 mode and the old function // is an extern inline function. // Don't complain about specializations. They are not supposed to have // storage classes. if (!isa(New) && !isa(Old) && New->getStorageClass() == SC_Static && Old->hasExternalFormalLinkage() && !New->getTemplateSpecializationInfo() && !canRedefineFunction(Old, getLangOpts())) { if (getLangOpts().MicrosoftExt) { Diag(New->getLocation(), diag::ext_static_non_static) << New; Diag(OldLocation, PrevDiag); } else { Diag(New->getLocation(), diag::err_static_non_static) << New; Diag(OldLocation, PrevDiag); return true; } } if (New->hasAttr() && !Old->hasAttr()) { Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) << New->getDeclName(); notePreviousDefinition(Old->getLocation(), New->getLocation()); New->dropAttr(); } // If a function is first declared with a calling convention, but is later // declared or defined without one, all following decls assume the calling // convention of the first. // // It's OK if a function is first declared without a calling convention, // but is later declared or defined with the default calling convention. // // To test if either decl has an explicit calling convention, we look for // AttributedType sugar nodes on the type as written. If they are missing or // were canonicalized away, we assume the calling convention was implicit. // // Note also that we DO NOT return at this point, because we still have // other tests to run. QualType OldQType = Context.getCanonicalType(Old->getType()); QualType NewQType = Context.getCanonicalType(New->getType()); const FunctionType *OldType = cast(OldQType); const FunctionType *NewType = cast(NewQType); FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); bool RequiresAdjustment = false; if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) { FunctionDecl *First = Old->getFirstDecl(); const FunctionType *FT = First->getType().getCanonicalType()->castAs(); FunctionType::ExtInfo FI = FT->getExtInfo(); bool NewCCExplicit = getCallingConvAttributedType(New->getType()); if (!NewCCExplicit) { // Inherit the CC from the previous declaration if it was specified // there but not here. NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); RequiresAdjustment = true; } else { // Calling conventions aren't compatible, so complain. bool FirstCCExplicit = getCallingConvAttributedType(First->getType()); Diag(New->getLocation(), diag::err_cconv_change) << FunctionType::getNameForCallConv(NewTypeInfo.getCC()) << !FirstCCExplicit << (!FirstCCExplicit ? "" : FunctionType::getNameForCallConv(FI.getCC())); // Put the note on the first decl, since it is the one that matters. Diag(First->getLocation(), diag::note_previous_declaration); return true; } } // FIXME: diagnose the other way around? if (OldTypeInfo.getNoReturn() && !NewTypeInfo.getNoReturn()) { NewTypeInfo = NewTypeInfo.withNoReturn(true); RequiresAdjustment = true; } // Merge regparm attribute. if (OldTypeInfo.getHasRegParm() != NewTypeInfo.getHasRegParm() || OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { if (NewTypeInfo.getHasRegParm()) { Diag(New->getLocation(), diag::err_regparm_mismatch) << NewType->getRegParmType() << OldType->getRegParmType(); Diag(OldLocation, diag::note_previous_declaration); return true; } NewTypeInfo = NewTypeInfo.withRegParm(OldTypeInfo.getRegParm()); RequiresAdjustment = true; } // Merge ns_returns_retained attribute. if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) { if (NewTypeInfo.getProducesResult()) { Diag(New->getLocation(), diag::err_function_attribute_mismatch) << "'ns_returns_retained'"; Diag(OldLocation, diag::note_previous_declaration); return true; } NewTypeInfo = NewTypeInfo.withProducesResult(true); RequiresAdjustment = true; } if (OldTypeInfo.getNoCallerSavedRegs() != NewTypeInfo.getNoCallerSavedRegs()) { if (NewTypeInfo.getNoCallerSavedRegs()) { AnyX86NoCallerSavedRegistersAttr *Attr = New->getAttr(); Diag(New->getLocation(), diag::err_function_attribute_mismatch) << Attr; Diag(OldLocation, diag::note_previous_declaration); return true; } NewTypeInfo = NewTypeInfo.withNoCallerSavedRegs(true); RequiresAdjustment = true; } if (RequiresAdjustment) { const FunctionType *AdjustedType = New->getType()->getAs(); AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo); New->setType(QualType(AdjustedType, 0)); NewQType = Context.getCanonicalType(New->getType()); NewType = cast(NewQType); } // If this redeclaration makes the function inline, we may need to add it to // UndefinedButUsed. if (!Old->isInlined() && New->isInlined() && !New->hasAttr() && !getLangOpts().GNUInline && Old->isUsed(false) && !Old->isDefined() && !New->isThisDeclarationADefinition()) UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(), SourceLocation())); // If this redeclaration makes it newly gnu_inline, we don't want to warn // about it. if (New->hasAttr() && Old->isInlined() && !Old->hasAttr()) { UndefinedButUsed.erase(Old->getCanonicalDecl()); } // If pass_object_size params don't match up perfectly, this isn't a valid // redeclaration. if (Old->getNumParams() > 0 && Old->getNumParams() == New->getNumParams() && !hasIdenticalPassObjectSizeAttrs(Old, New)) { Diag(New->getLocation(), diag::err_different_pass_object_size_params) << New->getDeclName(); Diag(OldLocation, PrevDiag) << Old << Old->getType(); return true; } if (getLangOpts().CPlusPlus) { // C++1z [over.load]p2 // Certain function declarations cannot be overloaded: // -- Function declarations that differ only in the return type, // the exception specification, or both cannot be overloaded. // Check the exception specifications match. This may recompute the type of // both Old and New if it resolved exception specifications, so grab the // types again after this. Because this updates the type, we do this before // any of the other checks below, which may update the "de facto" NewQType // but do not necessarily update the type of New. if (CheckEquivalentExceptionSpec(Old, New)) return true; OldQType = Context.getCanonicalType(Old->getType()); NewQType = Context.getCanonicalType(New->getType()); // Go back to the type source info to compare the declared return types, // per C++1y [dcl.type.auto]p13: // Redeclarations or specializations of a function or function template // with a declared return type that uses a placeholder type shall also // use that placeholder, not a deduced type. QualType OldDeclaredReturnType = (Old->getTypeSourceInfo() ? Old->getTypeSourceInfo()->getType()->castAs() : OldType)->getReturnType(); QualType NewDeclaredReturnType = (New->getTypeSourceInfo() ? New->getTypeSourceInfo()->getType()->castAs() : NewType)->getReturnType(); if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) && !((NewQType->isDependentType() || OldQType->isDependentType()) && New->isLocalExternDecl())) { QualType ResQT; if (NewDeclaredReturnType->isObjCObjectPointerType() && OldDeclaredReturnType->isObjCObjectPointerType()) ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); if (ResQT.isNull()) { if (New->isCXXClassMember() && New->isOutOfLine()) Diag(New->getLocation(), diag::err_member_def_does_not_match_ret_type) << New << New->getReturnTypeSourceRange(); else Diag(New->getLocation(), diag::err_ovl_diff_return_type) << New->getReturnTypeSourceRange(); Diag(OldLocation, PrevDiag) << Old << Old->getType() << Old->getReturnTypeSourceRange(); return true; } else NewQType = ResQT; } QualType OldReturnType = OldType->getReturnType(); QualType NewReturnType = cast(NewQType)->getReturnType(); if (OldReturnType != NewReturnType) { // If this function has a deduced return type and has already been // defined, copy the deduced value from the old declaration. AutoType *OldAT = Old->getReturnType()->getContainedAutoType(); if (OldAT && OldAT->isDeduced()) { New->setType( SubstAutoType(New->getType(), OldAT->isDependentType() ? Context.DependentTy : OldAT->getDeducedType())); NewQType = Context.getCanonicalType( SubstAutoType(NewQType, OldAT->isDependentType() ? Context.DependentTy : OldAT->getDeducedType())); } } const CXXMethodDecl *OldMethod = dyn_cast(Old); CXXMethodDecl *NewMethod = dyn_cast(New); if (OldMethod && NewMethod) { // Preserve triviality. NewMethod->setTrivial(OldMethod->isTrivial()); // MSVC allows explicit template specialization at class scope: // 2 CXXMethodDecls referring to the same function will be injected. // We don't want a redeclaration error. bool IsClassScopeExplicitSpecialization = OldMethod->isFunctionTemplateSpecialization() && NewMethod->isFunctionTemplateSpecialization(); bool isFriend = NewMethod->getFriendObjectKind(); if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord() && !IsClassScopeExplicitSpecialization) { // -- Member function declarations with the same name and the // same parameter types cannot be overloaded if any of them // is a static member function declaration. if (OldMethod->isStatic() != NewMethod->isStatic()) { Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); Diag(OldLocation, PrevDiag) << Old << Old->getType(); return true; } // C++ [class.mem]p1: // [...] A member shall not be declared twice in the // member-specification, except that a nested class or member // class template can be declared and then later defined. if (!inTemplateInstantiation()) { unsigned NewDiag; if (isa(OldMethod)) NewDiag = diag::err_constructor_redeclared; else if (isa(NewMethod)) NewDiag = diag::err_destructor_redeclared; else if (isa(NewMethod)) NewDiag = diag::err_conv_function_redeclared; else NewDiag = diag::err_member_redeclared; Diag(New->getLocation(), NewDiag); } else { Diag(New->getLocation(), diag::err_member_redeclared_in_instantiation) << New << New->getType(); } Diag(OldLocation, PrevDiag) << Old << Old->getType(); return true; // Complain if this is an explicit declaration of a special // member that was initially declared implicitly. // // As an exception, it's okay to befriend such methods in order // to permit the implicit constructor/destructor/operator calls. } else if (OldMethod->isImplicit()) { if (isFriend) { NewMethod->setImplicit(); } else { Diag(NewMethod->getLocation(), diag::err_definition_of_implicitly_declared_member) << New << getSpecialMember(OldMethod); return true; } } else if (OldMethod->getFirstDecl()->isExplicitlyDefaulted() && !isFriend) { Diag(NewMethod->getLocation(), diag::err_definition_of_explicitly_defaulted_member) << getSpecialMember(OldMethod); return true; } } // C++11 [dcl.attr.noreturn]p1: // The first declaration of a function shall specify the noreturn // attribute if any declaration of that function specifies the noreturn // attribute. const CXX11NoReturnAttr *NRA = New->getAttr(); if (NRA && !Old->hasAttr()) { Diag(NRA->getLocation(), diag::err_noreturn_missing_on_first_decl); Diag(Old->getFirstDecl()->getLocation(), diag::note_noreturn_missing_first_decl); } // C++11 [dcl.attr.depend]p2: // The first declaration of a function shall specify the // carries_dependency attribute for its declarator-id if any declaration // of the function specifies the carries_dependency attribute. const CarriesDependencyAttr *CDA = New->getAttr(); if (CDA && !Old->hasAttr()) { Diag(CDA->getLocation(), diag::err_carries_dependency_missing_on_first_decl) << 0/*Function*/; Diag(Old->getFirstDecl()->getLocation(), diag::note_carries_dependency_missing_first_decl) << 0/*Function*/; } // (C++98 8.3.5p3): // All declarations for a function shall agree exactly in both the // return type and the parameter-type-list. // We also want to respect all the extended bits except noreturn. // noreturn should now match unless the old type info didn't have it. QualType OldQTypeForComparison = OldQType; if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) { auto *OldType = OldQType->castAs(); const FunctionType *OldTypeForComparison = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true)); OldQTypeForComparison = QualType(OldTypeForComparison, 0); assert(OldQTypeForComparison.isCanonical()); } if (haveIncompatibleLanguageLinkages(Old, New)) { // As a special case, retain the language linkage from previous // declarations of a friend function as an extension. // // This liberal interpretation of C++ [class.friend]p3 matches GCC/MSVC // and is useful because there's otherwise no way to specify language // linkage within class scope. // // Check cautiously as the friend object kind isn't yet complete. if (New->getFriendObjectKind() != Decl::FOK_None) { Diag(New->getLocation(), diag::ext_retained_language_linkage) << New; Diag(OldLocation, PrevDiag); } else { Diag(New->getLocation(), diag::err_different_language_linkage) << New; Diag(OldLocation, PrevDiag); return true; } } if (OldQTypeForComparison == NewQType) return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); if ((NewQType->isDependentType() || OldQType->isDependentType()) && New->isLocalExternDecl()) { // It's OK if we couldn't merge types for a local function declaraton // if either the old or new type is dependent. We'll merge the types // when we instantiate the function. return false; } // Fall through for conflicting redeclarations and redefinitions. } // C: Function types need to be compatible, not identical. This handles // duplicate function decls like "void f(int); void f(enum X);" properly. if (!getLangOpts().CPlusPlus && Context.typesAreCompatible(OldQType, NewQType)) { const FunctionType *OldFuncType = OldQType->getAs(); const FunctionType *NewFuncType = NewQType->getAs(); const FunctionProtoType *OldProto = nullptr; if (MergeTypeWithOld && isa(NewFuncType) && (OldProto = dyn_cast(OldFuncType))) { // The old declaration provided a function prototype, but the // new declaration does not. Merge in the prototype. assert(!OldProto->hasExceptionSpec() && "Exception spec in C"); SmallVector ParamTypes(OldProto->param_types()); NewQType = Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes, OldProto->getExtProtoInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); // Synthesize parameters with the same types. SmallVector Params; for (const auto &ParamType : OldProto->param_types()) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(), nullptr, ParamType, /*TInfo=*/nullptr, SC_None, nullptr); Param->setScopeInfo(0, Params.size()); Param->setImplicit(); Params.push_back(Param); } New->setParams(Params); } return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); } // GNU C permits a K&R definition to follow a prototype declaration // if the declared types of the parameters in the K&R definition // match the types in the prototype declaration, even when the // promoted types of the parameters from the K&R definition differ // from the types in the prototype. GCC then keeps the types from // the prototype. // // If a variadic prototype is followed by a non-variadic K&R definition, // the K&R definition becomes variadic. This is sort of an edge case, but // it's legal per the standard depending on how you read C99 6.7.5.3p15 and // C99 6.9.1p8. if (!getLangOpts().CPlusPlus && Old->hasPrototype() && !New->hasPrototype() && New->getType()->getAs() && Old->getNumParams() == New->getNumParams()) { SmallVector ArgTypes; SmallVector Warnings; const FunctionProtoType *OldProto = Old->getType()->getAs(); const FunctionProtoType *NewProto = New->getType()->getAs(); // Determine whether this is the GNU C extension. QualType MergedReturn = Context.mergeTypes(OldProto->getReturnType(), NewProto->getReturnType()); bool LooseCompatible = !MergedReturn.isNull(); for (unsigned Idx = 0, End = Old->getNumParams(); LooseCompatible && Idx != End; ++Idx) { ParmVarDecl *OldParm = Old->getParamDecl(Idx); ParmVarDecl *NewParm = New->getParamDecl(Idx); if (Context.typesAreCompatible(OldParm->getType(), NewProto->getParamType(Idx))) { ArgTypes.push_back(NewParm->getType()); } else if (Context.typesAreCompatible(OldParm->getType(), NewParm->getType(), /*CompareUnqualified=*/true)) { GNUCompatibleParamWarning Warn = { OldParm, NewParm, NewProto->getParamType(Idx) }; Warnings.push_back(Warn); ArgTypes.push_back(NewParm->getType()); } else LooseCompatible = false; } if (LooseCompatible) { for (unsigned Warn = 0; Warn < Warnings.size(); ++Warn) { Diag(Warnings[Warn].NewParm->getLocation(), diag::ext_param_promoted_not_compatible_with_prototype) << Warnings[Warn].PromotedType << Warnings[Warn].OldParm->getType(); if (Warnings[Warn].OldParm->getLocation().isValid()) Diag(Warnings[Warn].OldParm->getLocation(), diag::note_previous_declaration); } if (MergeTypeWithOld) New->setType(Context.getFunctionType(MergedReturn, ArgTypes, OldProto->getExtProtoInfo())); return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); } // Fall through to diagnose conflicting types. } // A function that has already been declared has been redeclared or // defined with a different type; show an appropriate diagnostic. // If the previous declaration was an implicitly-generated builtin // declaration, then at the very least we should use a specialized note. unsigned BuiltinID; if (Old->isImplicit() && (BuiltinID = Old->getBuiltinID())) { // If it's actually a library-defined builtin function like 'malloc' // or 'printf', just warn about the incompatible redeclaration. if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New; Diag(OldLocation, diag::note_previous_builtin_declaration) << Old << Old->getType(); // If this is a global redeclaration, just forget hereafter // about the "builtin-ness" of the function. // // Doing this for local extern declarations is problematic. If // the builtin declaration remains visible, a second invalid // local declaration will produce a hard error; if it doesn't // remain visible, a single bogus local redeclaration (which is // actually only a warning) could break all the downstream code. if (!New->getLexicalDeclContext()->isFunctionOrMethod()) New->getIdentifier()->revertBuiltin(); return false; } PrevDiag = diag::note_previous_builtin_declaration; } Diag(New->getLocation(), diag::err_conflicting_types) << New->getDeclName(); Diag(OldLocation, PrevDiag) << Old << Old->getType(); return true; } /// \brief Completes the merge of two function declarations that are /// known to be compatible. /// /// This routine handles the merging of attributes and other /// properties of function declarations from the old declaration to /// the new declaration, once we know that New is in fact a /// redeclaration of Old. /// /// \returns false bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, Scope *S, bool MergeTypeWithOld) { // Merge the attributes mergeDeclAttributes(New, Old); // Merge "pure" flag. if (Old->isPure()) New->setPure(); // Merge "used" flag. if (Old->getMostRecentDecl()->isUsed(false)) New->setIsUsed(); // Merge attributes from the parameters. These can mismatch with K&R // declarations. if (New->getNumParams() == Old->getNumParams()) for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) { ParmVarDecl *NewParam = New->getParamDecl(i); ParmVarDecl *OldParam = Old->getParamDecl(i); mergeParamDeclAttributes(NewParam, OldParam, *this); mergeParamDeclTypes(NewParam, OldParam, *this); } if (getLangOpts().CPlusPlus) return MergeCXXFunctionDecl(New, Old, S); // Merge the function types so the we get the composite types for the return // and argument types. Per C11 6.2.7/4, only update the type if the old decl // was visible. QualType Merged = Context.mergeTypes(Old->getType(), New->getType()); if (!Merged.isNull() && MergeTypeWithOld) New->setType(Merged); return false; } void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, ObjCMethodDecl *oldMethod) { // Merge the attributes, including deprecated/unavailable AvailabilityMergeKind MergeKind = isa(oldMethod->getDeclContext()) ? AMK_ProtocolImplementation : isa(newMethod->getDeclContext()) ? AMK_Redeclaration : AMK_Override; mergeDeclAttributes(newMethod, oldMethod, MergeKind); // Merge attributes from the parameters. ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(), oe = oldMethod->param_end(); for (ObjCMethodDecl::param_iterator ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne && oi != oe; ++ni, ++oi) mergeParamDeclAttributes(*ni, *oi, *this); CheckObjCMethodOverride(newMethod, oldMethod); } static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) { assert(!S.Context.hasSameType(New->getType(), Old->getType())); S.Diag(New->getLocation(), New->isThisDeclarationADefinition() ? diag::err_redefinition_different_type : diag::err_redeclaration_different_type) << New->getDeclName() << New->getType() << Old->getType(); diag::kind PrevDiag; SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = getNoteDiagForInvalidRedeclaration(Old, New); S.Diag(OldLocation, PrevDiag); New->setInvalidDecl(); } /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and /// scope as a previous declaration 'Old'. Figure out how to merge their types, /// emitting diagnostics as appropriate. /// /// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back /// to here in AddInitializerToDecl. We can't check them before the initializer /// is attached. void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld) { if (New->isInvalidDecl() || Old->isInvalidDecl()) return; QualType MergedT; if (getLangOpts().CPlusPlus) { if (New->getType()->isUndeducedType()) { // We don't know what the new type is until the initializer is attached. return; } else if (Context.hasSameType(New->getType(), Old->getType())) { // These could still be something that needs exception specs checked. return MergeVarDeclExceptionSpecs(New, Old); } // C++ [basic.link]p10: // [...] the types specified by all declarations referring to a given // object or function shall be identical, except that declarations for an // array object can specify array types that differ by the presence or // absence of a major array bound (8.3.4). else if (Old->getType()->isArrayType() && New->getType()->isArrayType()) { const ArrayType *OldArray = Context.getAsArrayType(Old->getType()); const ArrayType *NewArray = Context.getAsArrayType(New->getType()); // We are merging a variable declaration New into Old. If it has an array // bound, and that bound differs from Old's bound, we should diagnose the // mismatch. if (!NewArray->isIncompleteArrayType() && !NewArray->isDependentType()) { for (VarDecl *PrevVD = Old->getMostRecentDecl(); PrevVD; PrevVD = PrevVD->getPreviousDecl()) { const ArrayType *PrevVDTy = Context.getAsArrayType(PrevVD->getType()); if (PrevVDTy->isIncompleteArrayType() || PrevVDTy->isDependentType()) continue; if (!Context.hasSameType(NewArray, PrevVDTy)) return diagnoseVarDeclTypeMismatch(*this, New, PrevVD); } } if (OldArray->isIncompleteArrayType() && NewArray->isArrayType()) { if (Context.hasSameType(OldArray->getElementType(), NewArray->getElementType())) MergedT = New->getType(); } // FIXME: Check visibility. New is hidden but has a complete type. If New // has no array bound, it should not inherit one from Old, if Old is not // visible. else if (OldArray->isArrayType() && NewArray->isIncompleteArrayType()) { if (Context.hasSameType(OldArray->getElementType(), NewArray->getElementType())) MergedT = Old->getType(); } } else if (New->getType()->isObjCObjectPointerType() && Old->getType()->isObjCObjectPointerType()) { MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); } } else { // C 6.2.7p2: // All declarations that refer to the same object or function shall have // compatible type. MergedT = Context.mergeTypes(New->getType(), Old->getType()); } if (MergedT.isNull()) { // It's OK if we couldn't merge types if either type is dependent, for a // block-scope variable. In other cases (static data members of class // templates, variable templates, ...), we require the types to be // equivalent. // FIXME: The C++ standard doesn't say anything about this. if ((New->getType()->isDependentType() || Old->getType()->isDependentType()) && New->isLocalVarDecl()) { // If the old type was dependent, we can't merge with it, so the new type // becomes dependent for now. We'll reproduce the original type when we // instantiate the TypeSourceInfo for the variable. if (!New->getType()->isDependentType() && MergeTypeWithOld) New->setType(Context.DependentTy); return; } return diagnoseVarDeclTypeMismatch(*this, New, Old); } // Don't actually update the type on the new declaration if the old // declaration was an extern declaration in a different scope. if (MergeTypeWithOld) New->setType(MergedT); } static bool mergeTypeWithPrevious(Sema &S, VarDecl *NewVD, VarDecl *OldVD, LookupResult &Previous) { // C11 6.2.7p4: // For an identifier with internal or external linkage declared // in a scope in which a prior declaration of that identifier is // visible, if the prior declaration specifies internal or // external linkage, the type of the identifier at the later // declaration becomes the composite type. // // If the variable isn't visible, we do not merge with its type. if (Previous.isShadowed()) return false; if (S.getLangOpts().CPlusPlus) { // C++11 [dcl.array]p3: // If there is a preceding declaration of the entity in the same // scope in which the bound was specified, an omitted array bound // is taken to be the same as in that earlier declaration. return NewVD->isPreviousDeclInSameBlockScope() || (!OldVD->getLexicalDeclContext()->isFunctionOrMethod() && !NewVD->getLexicalDeclContext()->isFunctionOrMethod()); } else { // If the old declaration was function-local, don't merge with its // type unless we're in the same function. return !OldVD->getLexicalDeclContext()->isFunctionOrMethod() || OldVD->getLexicalDeclContext() == NewVD->getLexicalDeclContext(); } } /// MergeVarDecl - We just parsed a variable 'New' which has the same name /// and scope as a previous declaration 'Old'. Figure out how to resolve this /// situation, merging decls or emitting diagnostics as appropriate. /// /// Tentative definition rules (C99 6.9.2p2) are checked by /// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative /// definitions here, since the initializer hasn't been attached. /// void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // If the new decl is already invalid, don't do any other checking. if (New->isInvalidDecl()) return; if (!shouldLinkPossiblyHiddenDecl(Previous, New)) return; VarTemplateDecl *NewTemplate = New->getDescribedVarTemplate(); // Verify the old decl was also a variable or variable template. VarDecl *Old = nullptr; VarTemplateDecl *OldTemplate = nullptr; if (Previous.isSingleResult()) { if (NewTemplate) { OldTemplate = dyn_cast(Previous.getFoundDecl()); Old = OldTemplate ? OldTemplate->getTemplatedDecl() : nullptr; if (auto *Shadow = dyn_cast(Previous.getRepresentativeDecl())) if (checkUsingShadowRedecl(*this, Shadow, NewTemplate)) return New->setInvalidDecl(); } else { Old = dyn_cast(Previous.getFoundDecl()); if (auto *Shadow = dyn_cast(Previous.getRepresentativeDecl())) if (checkUsingShadowRedecl(*this, Shadow, New)) return New->setInvalidDecl(); } } if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); notePreviousDefinition(Previous.getRepresentativeDecl()->getLocation(), New->getLocation()); return New->setInvalidDecl(); } // Ensure the template parameters are compatible. if (NewTemplate && !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), OldTemplate->getTemplateParameters(), /*Complain=*/true, TPL_TemplateMatch)) return New->setInvalidDecl(); // C++ [class.mem]p1: // A member shall not be declared twice in the member-specification [...] // // Here, we need only consider static data members. if (Old->isStaticDataMember() && !New->isOutOfLine()) { Diag(New->getLocation(), diag::err_duplicate_member) << New->getIdentifier(); Diag(Old->getLocation(), diag::note_previous_declaration); New->setInvalidDecl(); } mergeDeclAttributes(New, Old); // Warn if an already-declared variable is made a weak_import in a subsequent // declaration if (New->hasAttr() && Old->getStorageClass() == SC_None && !Old->hasAttr()) { Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); notePreviousDefinition(Old->getLocation(), New->getLocation()); // Remove weak_import attribute on new declaration. New->dropAttr(); } if (New->hasAttr() && !Old->hasAttr()) { Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) << New->getDeclName(); notePreviousDefinition(Old->getLocation(), New->getLocation()); New->dropAttr(); } // Merge the types. VarDecl *MostRecent = Old->getMostRecentDecl(); if (MostRecent != Old) { MergeVarDeclTypes(New, MostRecent, mergeTypeWithPrevious(*this, New, MostRecent, Previous)); if (New->isInvalidDecl()) return; } MergeVarDeclTypes(New, Old, mergeTypeWithPrevious(*this, New, Old, Previous)); if (New->isInvalidDecl()) return; diag::kind PrevDiag; SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = getNoteDiagForInvalidRedeclaration(Old, New); // [dcl.stc]p8: Check if we have a non-static decl followed by a static. if (New->getStorageClass() == SC_Static && !New->isStaticDataMember() && Old->hasExternalFormalLinkage()) { if (getLangOpts().MicrosoftExt) { Diag(New->getLocation(), diag::ext_static_non_static) << New->getDeclName(); Diag(OldLocation, PrevDiag); } else { Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } } // C99 6.2.2p4: // For an identifier declared with the storage-class specifier // extern in a scope in which a prior declaration of that // identifier is visible,23) if the prior declaration specifies // internal or external linkage, the linkage of the identifier at // the later declaration is the same as the linkage specified at // the prior declaration. If no prior declaration is visible, or // if the prior declaration specifies no linkage, then the // identifier has external linkage. if (New->hasExternalStorage() && Old->hasLinkage()) /* Okay */; else if (New->getCanonicalDecl()->getStorageClass() != SC_Static && !New->isStaticDataMember() && Old->getCanonicalDecl()->getStorageClass() == SC_Static) { Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } // Check if extern is followed by non-extern and vice-versa. if (New->hasExternalStorage() && !Old->hasLinkage() && Old->isLocalVarDeclOrParm()) { Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } if (Old->hasLinkage() && New->isLocalVarDeclOrParm() && !New->hasExternalStorage()) { Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still // need to check for mismatches. if (!New->hasExternalStorage() && !New->isFileVarDecl() && // Don't complain about out-of-line definitions of static members. !(Old->getLexicalDeclContext()->isRecord() && !New->getLexicalDeclContext()->isRecord())) { Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } if (New->isInline() && !Old->getMostRecentDecl()->isInline()) { if (VarDecl *Def = Old->getDefinition()) { // C++1z [dcl.fcn.spec]p4: // If the definition of a variable appears in a translation unit before // its first declaration as inline, the program is ill-formed. Diag(New->getLocation(), diag::err_inline_decl_follows_def) << New; Diag(Def->getLocation(), diag::note_previous_definition); } } // If this redeclaration makes the function inline, we may need to add it to // UndefinedButUsed. if (!Old->isInline() && New->isInline() && Old->isUsed(false) && !Old->getDefinition() && !New->isThisDeclarationADefinition()) UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(), SourceLocation())); if (New->getTLSKind() != Old->getTLSKind()) { if (!Old->getTLSKind()) { Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); Diag(OldLocation, PrevDiag); } else if (!New->getTLSKind()) { Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); Diag(OldLocation, PrevDiag); } else { // Do not allow redeclaration to change the variable between requiring // static and dynamic initialization. // FIXME: GCC allows this, but uses the TLS keyword on the first // declaration to determine the kind. Do we need to be compatible here? Diag(New->getLocation(), diag::err_thread_thread_different_kind) << New->getDeclName() << (New->getTLSKind() == VarDecl::TLS_Dynamic); Diag(OldLocation, PrevDiag); } } // C++ doesn't have tentative definitions, so go right ahead and check here. if (getLangOpts().CPlusPlus && New->isThisDeclarationADefinition() == VarDecl::Definition) { if (Old->isStaticDataMember() && Old->getCanonicalDecl()->isInline() && Old->getCanonicalDecl()->isConstexpr()) { // This definition won't be a definition any more once it's been merged. Diag(New->getLocation(), diag::warn_deprecated_redundant_constexpr_static_def); } else if (VarDecl *Def = Old->getDefinition()) { if (checkVarDeclRedefinition(Def, New)) return; } } if (haveIncompatibleLanguageLinkages(Old, New)) { Diag(New->getLocation(), diag::err_different_language_linkage) << New; Diag(OldLocation, PrevDiag); New->setInvalidDecl(); return; } // Merge "used" flag. if (Old->getMostRecentDecl()->isUsed(false)) New->setIsUsed(); // Keep a chain of previous declarations. New->setPreviousDecl(Old); if (NewTemplate) NewTemplate->setPreviousDecl(OldTemplate); // Inherit access appropriately. New->setAccess(Old->getAccess()); if (NewTemplate) NewTemplate->setAccess(New->getAccess()); if (Old->isInline()) New->setImplicitlyInline(); } void Sema::notePreviousDefinition(SourceLocation Old, SourceLocation New) { SourceManager &SrcMgr = getSourceManager(); auto FNewDecLoc = SrcMgr.getDecomposedLoc(New); auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old); auto *FNew = SrcMgr.getFileEntryForID(FNewDecLoc.first); auto *FOld = SrcMgr.getFileEntryForID(FOldDecLoc.first); auto &HSI = PP.getHeaderSearchInfo(); StringRef HdrFilename = SrcMgr.getFilename(SrcMgr.getSpellingLoc(Old)); auto noteFromModuleOrInclude = [&](SourceLocation &Loc, SourceLocation &IncLoc) -> bool { Module *Mod = nullptr; // Redefinition errors with modules are common with non modular mapped // headers, example: a non-modular header H in module A that also gets // included directly in a TU. Pointing twice to the same header/definition // is confusing, try to get better diagnostics when modules is on. if (getLangOpts().Modules) { auto ModLoc = SrcMgr.getModuleImportLoc(Old); if (!ModLoc.first.isInvalid()) Mod = HSI.getModuleMap().inferModuleFromLocation( FullSourceLoc(Loc, SrcMgr)); } if (IncLoc.isValid()) { if (Mod) { Diag(IncLoc, diag::note_redefinition_modules_same_file) << HdrFilename.str() << Mod->getFullModuleName(); if (!Mod->DefinitionLoc.isInvalid()) Diag(Mod->DefinitionLoc, diag::note_defined_here) << Mod->getFullModuleName(); } else { Diag(IncLoc, diag::note_redefinition_include_same_file) << HdrFilename.str(); } return true; } return false; }; // Is it the same file and same offset? Provide more information on why // this leads to a redefinition error. bool EmittedDiag = false; if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) { SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first); SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first); EmittedDiag = noteFromModuleOrInclude(Old, OldIncLoc); EmittedDiag |= noteFromModuleOrInclude(New, NewIncLoc); // If the header has no guards, emit a note suggesting one. if (FOld && !HSI.isFileMultipleIncludeGuarded(FOld)) Diag(Old, diag::note_use_ifdef_guards); if (EmittedDiag) return; } // Redefinition coming from different files or couldn't do better above. Diag(Old, diag::note_previous_definition); } /// We've just determined that \p Old and \p New both appear to be definitions /// of the same variable. Either diagnose or fix the problem. bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) { if (!hasVisibleDefinition(Old) && (New->getFormalLinkage() == InternalLinkage || New->isInline() || New->getDescribedVarTemplate() || New->getNumTemplateParameterLists() || New->getDeclContext()->isDependentContext())) { // The previous definition is hidden, and multiple definitions are // permitted (in separate TUs). Demote this to a declaration. New->demoteThisDefinitionToDeclaration(); // Make the canonical definition visible. if (auto *OldTD = Old->getDescribedVarTemplate()) makeMergedDefinitionVisible(OldTD); makeMergedDefinitionVisible(Old); return false; } else { Diag(New->getLocation(), diag::err_redefinition) << New; notePreviousDefinition(Old->getLocation(), New->getLocation()); New->setInvalidDecl(); return true; } } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. Decl * Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, RecordDecl *&AnonRecord) { return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg(), false, AnonRecord); } // The MS ABI changed between VS2013 and VS2015 with regard to numbers used to // disambiguate entities defined in different scopes. // While the VS2015 ABI fixes potential miscompiles, it is also breaks // compatibility. // We will pick our mangling number depending on which version of MSVC is being // targeted. static unsigned getMSManglingNumber(const LangOptions &LO, Scope *S) { return LO.isCompatibleWithMSVC(LangOptions::MSVC2015) ? S->getMSCurManglingNumber() : S->getMSLastManglingNumber(); } void Sema::handleTagNumbering(const TagDecl *Tag, Scope *TagScope) { if (!Context.getLangOpts().CPlusPlus) return; if (isa(Tag->getParent())) { // If this tag is the direct child of a class, number it if // it is anonymous. if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl()) return; MangleNumberingContext &MCtx = Context.getManglingNumberContext(Tag->getParent()); Context.setManglingNumber( Tag, MCtx.getManglingNumber( Tag, getMSManglingNumber(getLangOpts(), TagScope))); return; } // If this tag isn't a direct child of a class, number it if it is local. Decl *ManglingContextDecl; if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext( Tag->getDeclContext(), ManglingContextDecl)) { Context.setManglingNumber( Tag, MCtx->getManglingNumber( Tag, getMSManglingNumber(getLangOpts(), TagScope))); } } void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, TypedefNameDecl *NewTD) { if (TagFromDeclSpec->isInvalidDecl()) return; // Do nothing if the tag already has a name for linkage purposes. if (TagFromDeclSpec->hasNameForLinkage()) return; // A well-formed anonymous tag must always be a TUK_Definition. assert(TagFromDeclSpec->isThisDeclarationADefinition()); // The type must match the tag exactly; no qualifiers allowed. if (!Context.hasSameType(NewTD->getUnderlyingType(), Context.getTagDeclType(TagFromDeclSpec))) { if (getLangOpts().CPlusPlus) Context.addTypedefNameForUnnamedTagDecl(TagFromDeclSpec, NewTD); return; } // If we've already computed linkage for the anonymous tag, then // adding a typedef name for the anonymous decl can change that // linkage, which might be a serious problem. Diagnose this as // unsupported and ignore the typedef name. TODO: we should // pursue this as a language defect and establish a formal rule // for how to handle it. if (TagFromDeclSpec->hasLinkageBeenComputed()) { Diag(NewTD->getLocation(), diag::err_typedef_changes_linkage); SourceLocation tagLoc = TagFromDeclSpec->getInnerLocStart(); tagLoc = getLocForEndOfToken(tagLoc); llvm::SmallString<40> textToInsert; textToInsert += ' '; textToInsert += NewTD->getIdentifier()->getName(); Diag(tagLoc, diag::note_typedef_changes_linkage) << FixItHint::CreateInsertion(tagLoc, textToInsert); return; } // Otherwise, set this is the anon-decl typedef for the tag. TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD); } static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) { switch (T) { case DeclSpec::TST_class: return 0; case DeclSpec::TST_struct: return 1; case DeclSpec::TST_interface: return 2; case DeclSpec::TST_union: return 3; case DeclSpec::TST_enum: return 4; default: llvm_unreachable("unexpected type specifier"); } } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. It also accepts template /// parameters to cope with template friend declarations. Decl * Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation, RecordDecl *&AnonRecord) { Decl *TagD = nullptr; TagDecl *Tag = nullptr; if (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct || DS.getTypeSpecType() == DeclSpec::TST_interface || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { TagD = DS.getRepAsDecl(); if (!TagD) // We probably had an error return nullptr; // Note that the above type specs guarantee that the // type rep is a Decl, whereas in many of the others // it's a Type. if (isa(TagD)) Tag = cast(TagD); else if (ClassTemplateDecl *CTD = dyn_cast(TagD)) Tag = CTD->getTemplatedDecl(); } if (Tag) { handleTagNumbering(Tag, S); Tag->setFreeStanding(); if (Tag->isInvalidDecl()) return Tag; } if (unsigned TypeQuals = DS.getTypeQualifiers()) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from object // or incomplete types shall not be restrict-qualified." if (TypeQuals & DeclSpec::TQ_restrict) Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer_noarg) << DS.getSourceRange(); } if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) << getLangOpts().CPlusPlus1z; if (DS.isConstexprSpecified()) { // C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations // and definitions of functions and variables. if (Tag) Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); // Don't emit warnings after this error. return TagD; } if (DS.isConceptSpecified()) { // C++ Concepts TS [dcl.spec.concept]p1: A concept definition refers to // either a function concept and its definition or a variable concept and // its initializer. Diag(DS.getConceptSpecLoc(), diag::err_concept_wrong_decl_kind); return TagD; } DiagnoseFunctionSpecifiers(DS); if (DS.isFriendSpecified()) { // If we're dealing with a decl but not a TagDecl, assume that // whatever routines created it handled the friendship aspect. if (TagD && !Tag) return nullptr; return ActOnFriendTypeDecl(S, DS, TemplateParams); } const CXXScopeSpec &SS = DS.getTypeSpecScope(); bool IsExplicitSpecialization = !TemplateParams.empty() && TemplateParams.back()->size() == 0; if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && !IsExplicitInstantiation && !IsExplicitSpecialization && !isa(Tag)) { // Per C++ [dcl.type.elab]p1, a class declaration cannot have a // nested-name-specifier unless it is an explicit instantiation // or an explicit specialization. // // FIXME: We allow class template partial specializations here too, per the // obvious intent of DR1819. // // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either. Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier) << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << SS.getRange(); return nullptr; } // Track whether this decl-specifier declares anything. bool DeclaresAnything = true; // Handle anonymous struct definitions. if (RecordDecl *Record = dyn_cast_or_null(Tag)) { if (!Record->getDeclName() && Record->isCompleteDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOpts().CPlusPlus || Record->getDeclContext()->isRecord()) { // If CurContext is a DeclContext that can contain statements, // RecursiveASTVisitor won't visit the decls that // BuildAnonymousStructOrUnion() will put into CurContext. // Also store them here so that they can be part of the // DeclStmt that gets created in this case. // FIXME: Also return the IndirectFieldDecls created by // BuildAnonymousStructOr union, for the same reason? if (CurContext->isFunctionOrMethod()) AnonRecord = Record; return BuildAnonymousStructOrUnion(S, DS, AS, Record, Context.getPrintingPolicy()); } DeclaresAnything = false; } } // C11 6.7.2.1p2: // A struct-declaration that does not declare an anonymous structure or // anonymous union shall contain a struct-declarator-list. // // This rule also existed in C89 and C99; the grammar for struct-declaration // did not permit a struct-declaration without a struct-declarator-list. if (!getLangOpts().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { // Check for Microsoft C extension: anonymous struct/union member. // Handle 2 kinds of anonymous struct/union: // struct STRUCT; // union UNION; // and // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. // UNION_TYPE; <- where UNION_TYPE is a typedef union. if ((Tag && Tag->getDeclName()) || DS.getTypeSpecType() == DeclSpec::TST_typename) { RecordDecl *Record = nullptr; if (Tag) Record = dyn_cast(Tag); else if (const RecordType *RT = DS.getRepAsType().get()->getAsStructureType()) Record = RT->getDecl(); else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType()) Record = UT->getDecl(); if (Record && getLangOpts().MicrosoftExt) { Diag(DS.getLocStart(), diag::ext_ms_anonymous_record) << Record->isUnion() << DS.getSourceRange(); return BuildMicrosoftCAnonymousStruct(S, DS, Record); } DeclaresAnything = false; } } // Skip all the checks below if we have a type error. if (DS.getTypeSpecType() == DeclSpec::TST_error || (TagD && TagD->isInvalidDecl())) return TagD; if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) if (EnumDecl *Enum = dyn_cast_or_null(Tag)) if (Enum->enumerator_begin() == Enum->enumerator_end() && !Enum->getIdentifier() && !Enum->isInvalidDecl()) DeclaresAnything = false; if (!DS.isMissingDeclaratorOk()) { // Customize diagnostic for a typedef missing a name. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) Diag(DS.getLocStart(), diag::ext_typedef_without_a_name) << DS.getSourceRange(); else DeclaresAnything = false; } if (DS.isModulePrivateSpecified() && Tag && Tag->getDeclContext()->isFunctionOrMethod()) Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class) << Tag->getTagKind() << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc()); ActOnDocumentableDecl(TagD); // C 6.7/2: // A declaration [...] shall declare at least a declarator [...], a tag, // or the members of an enumeration. // C++ [dcl.dcl]p3: // [If there are no declarators], and except for the declaration of an // unnamed bit-field, the decl-specifier-seq shall introduce one or more // names into the program, or shall redeclare a name introduced by a // previous declaration. if (!DeclaresAnything) { // In C, we allow this as a (popular) extension / bug. Don't bother // producing further diagnostics for redundant qualifiers after this. Diag(DS.getLocStart(), diag::ext_no_declarators) << DS.getSourceRange(); return TagD; } // C++ [dcl.stc]p1: // If a storage-class-specifier appears in a decl-specifier-seq, [...] the // init-declarator-list of the declaration shall not be empty. // C++ [dcl.fct.spec]p1: // If a cv-qualifier appears in a decl-specifier-seq, the // init-declarator-list of the declaration shall not be empty. // // Spurious qualifiers here appear to be valid in C. unsigned DiagID = diag::warn_standalone_specifier; if (getLangOpts().CPlusPlus) DiagID = diag::ext_standalone_specifier; // Note that a linkage-specification sets a storage class, but // 'extern "C" struct foo;' is actually valid and not theoretically // useless. if (DeclSpec::SCS SCS = DS.getStorageClassSpec()) { if (SCS == DeclSpec::SCS_mutable) // Since mutable is not a viable storage class specifier in C, there is // no reason to treat it as an extension. Instead, diagnose as an error. Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_nonmember); else if (!DS.isExternInLinkageSpec() && SCS != DeclSpec::SCS_typedef) Diag(DS.getStorageClassSpecLoc(), DiagID) << DeclSpec::getSpecifierName(SCS); } if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) Diag(DS.getThreadStorageClassSpecLoc(), DiagID) << DeclSpec::getSpecifierName(TSCS); if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), DiagID) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getConstSpecLoc(), DiagID) << "volatile"; // Restrict is covered above. if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) Diag(DS.getAtomicSpecLoc(), DiagID) << "_Atomic"; if (DS.getTypeQualifiers() & DeclSpec::TQ_unaligned) Diag(DS.getUnalignedSpecLoc(), DiagID) << "__unaligned"; } // Warn about ignored type attributes, for example: // __attribute__((aligned)) struct A; // Attributes should be placed after tag to apply to type declaration. if (!DS.getAttributes().empty()) { DeclSpec::TST TypeSpecType = DS.getTypeSpecType(); if (TypeSpecType == DeclSpec::TST_class || TypeSpecType == DeclSpec::TST_struct || TypeSpecType == DeclSpec::TST_interface || TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { for (AttributeList* attrs = DS.getAttributes().getList(); attrs; attrs = attrs->getNext()) Diag(attrs->getLoc(), diag::warn_declspec_attribute_ignored) << attrs->getName() << GetDiagnosticTypeSpecifierID(TypeSpecType); } } return TagD; } /// We are trying to inject an anonymous member into the given scope; /// check if there's an existing declaration that can't be overloaded. /// /// \return true if this is a forbidden redeclaration static bool CheckAnonMemberRedeclaration(Sema &SemaRef, Scope *S, DeclContext *Owner, DeclarationName Name, SourceLocation NameLoc, bool IsUnion) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName, Sema::ForRedeclaration); if (!SemaRef.LookupName(R, S)) return false; // Pick a representative declaration. NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); assert(PrevDecl && "Expected a non-null Decl"); if (!SemaRef.isDeclInScope(PrevDecl, Owner, S)) return false; SemaRef.Diag(NameLoc, diag::err_anonymous_record_member_redecl) << IsUnion << Name; SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration); return true; } /// InjectAnonymousStructOrUnionMembers - Inject the members of the /// anonymous struct or union AnonRecord into the owning context Owner /// and scope S. This routine will be invoked just after we realize /// that an unnamed union or struct is actually an anonymous union or /// struct, e.g., /// /// @code /// union { /// int i; /// float f; /// }; // InjectAnonymousStructOrUnionMembers called here to inject i and /// // f into the surrounding scope.x /// @endcode /// /// This routine is recursive, injecting the names of nested anonymous /// structs/unions into the owning context and scope as well. static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner, RecordDecl *AnonRecord, AccessSpecifier AS, SmallVectorImpl &Chaining) { bool Invalid = false; // Look every FieldDecl and IndirectFieldDecl with a name. for (auto *D : AnonRecord->decls()) { if ((isa(D) || isa(D)) && cast(D)->getDeclName()) { ValueDecl *VD = cast(D); if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(), VD->getLocation(), AnonRecord->isUnion())) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be // distinct from the names of any other entity in the // scope in which the anonymous union is declared. Invalid = true; } else { // C++ [class.union]p2: // For the purpose of name lookup, after the anonymous union // definition, the members of the anonymous union are // considered to have been defined in the scope in which the // anonymous union is declared. unsigned OldChainingSize = Chaining.size(); if (IndirectFieldDecl *IF = dyn_cast(VD)) Chaining.append(IF->chain_begin(), IF->chain_end()); else Chaining.push_back(VD); assert(Chaining.size() >= 2); NamedDecl **NamedChain = new (SemaRef.Context)NamedDecl*[Chaining.size()]; for (unsigned i = 0; i < Chaining.size(); i++) NamedChain[i] = Chaining[i]; IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create( SemaRef.Context, Owner, VD->getLocation(), VD->getIdentifier(), VD->getType(), {NamedChain, Chaining.size()}); for (const auto *Attr : VD->attrs()) IndirectField->addAttr(Attr->clone(SemaRef.Context)); IndirectField->setAccess(AS); IndirectField->setImplicit(); SemaRef.PushOnScopeChains(IndirectField, S); // That includes picking up the appropriate access specifier. if (AS != AS_none) IndirectField->setAccess(AS); Chaining.resize(OldChainingSize); } } } return Invalid; } /// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to /// a VarDecl::StorageClass. Any error reporting is up to the caller: /// illegal input values are mapped to SC_None. static StorageClass StorageClassSpecToVarDeclStorageClass(const DeclSpec &DS) { DeclSpec::SCS StorageClassSpec = DS.getStorageClassSpec(); assert(StorageClassSpec != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class VarDecl."); switch (StorageClassSpec) { case DeclSpec::SCS_unspecified: return SC_None; case DeclSpec::SCS_extern: if (DS.isExternInLinkageSpec()) return SC_None; return SC_Extern; case DeclSpec::SCS_static: return SC_Static; case DeclSpec::SCS_auto: return SC_Auto; case DeclSpec::SCS_register: return SC_Register; case DeclSpec::SCS_private_extern: return SC_PrivateExtern; // Illegal SCSs map to None: error reporting is up to the caller. case DeclSpec::SCS_mutable: // Fall through. case DeclSpec::SCS_typedef: return SC_None; } llvm_unreachable("unknown storage class specifier"); } static SourceLocation findDefaultInitializer(const CXXRecordDecl *Record) { assert(Record->hasInClassInitializer()); for (const auto *I : Record->decls()) { const auto *FD = dyn_cast(I); if (const auto *IFD = dyn_cast(I)) FD = IFD->getAnonField(); if (FD && FD->hasInClassInitializer()) return FD->getLocation(); } llvm_unreachable("couldn't find in-class initializer"); } static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent, SourceLocation DefaultInitLoc) { if (!Parent->isUnion() || !Parent->hasInClassInitializer()) return; S.Diag(DefaultInitLoc, diag::err_multiple_mem_union_initialization); S.Diag(findDefaultInitializer(Parent), diag::note_previous_initializer) << 0; } static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent, CXXRecordDecl *AnonUnion) { if (!Parent->isUnion() || !Parent->hasInClassInitializer()) return; checkDuplicateDefaultInit(S, Parent, findDefaultInitializer(AnonUnion)); } /// BuildAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a C11 feature; anonymous structures /// are a C11 feature and GNU C++ extension. Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, AccessSpecifier AS, RecordDecl *Record, const PrintingPolicy &Policy) { DeclContext *Owner = Record->getDeclContext(); // Diagnose whether this anonymous struct/union is an extension. if (Record->isUnion() && !getLangOpts().CPlusPlus && !getLangOpts().C11) Diag(Record->getLocation(), diag::ext_anonymous_union); else if (!Record->isUnion() && getLangOpts().CPlusPlus) Diag(Record->getLocation(), diag::ext_gnu_anonymous_struct); else if (!Record->isUnion() && !getLangOpts().C11) Diag(Record->getLocation(), diag::ext_c11_anonymous_struct); // C and C++ require different kinds of checks for anonymous // structs/unions. bool Invalid = false; if (getLangOpts().CPlusPlus) { const char *PrevSpec = nullptr; unsigned DiagID; if (Record->isUnion()) { // C++ [class.union]p6: // Anonymous unions declared in a named namespace or in the // global namespace shall be declared static. if (DS.getStorageClassSpec() != DeclSpec::SCS_static && (isa(Owner) || (isa(Owner) && cast(Owner)->getDeclName()))) { Diag(Record->getLocation(), diag::err_anonymous_union_not_static) << FixItHint::CreateInsertion(Record->getLocation(), "static "); // Recover by adding 'static'. DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(), PrevSpec, DiagID, Policy); } // C++ [class.union]p6: // A storage class is not allowed in a declaration of an // anonymous union in a class scope. else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && isa(Owner)) { Diag(DS.getStorageClassSpecLoc(), diag::err_anonymous_union_with_storage_spec) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); // Recover by removing the storage specifier. DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified, SourceLocation(), PrevSpec, DiagID, Context.getPrintingPolicy()); } } // Ignore const/volatile/restrict qualifiers. if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "const" << FixItHint::CreateRemoval(DS.getConstSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "volatile" << FixItHint::CreateRemoval(DS.getVolatileSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "restrict" << FixItHint::CreateRemoval(DS.getRestrictSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) Diag(DS.getAtomicSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "_Atomic" << FixItHint::CreateRemoval(DS.getAtomicSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_unaligned) Diag(DS.getUnalignedSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "__unaligned" << FixItHint::CreateRemoval(DS.getUnalignedSpecLoc()); DS.ClearTypeQualifiers(); } // C++ [class.union]p2: // The member-specification of an anonymous union shall only // define non-static data members. [Note: nested types and // functions cannot be declared within an anonymous union. ] for (auto *Mem : Record->decls()) { if (auto *FD = dyn_cast(Mem)) { // C++ [class.union]p3: // An anonymous union shall not have private or protected // members (clause 11). assert(FD->getAccess() != AS_none); if (FD->getAccess() != AS_public) { Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member) << Record->isUnion() << (FD->getAccess() == AS_protected); Invalid = true; } // C++ [class.union]p1 // An object of a class with a non-trivial constructor, a non-trivial // copy constructor, a non-trivial destructor, or a non-trivial copy // assignment operator cannot be a member of a union, nor can an // array of such objects. if (CheckNontrivialField(FD)) Invalid = true; } else if (Mem->isImplicit()) { // Any implicit members are fine. } else if (isa(Mem) && Mem->getDeclContext() != Record) { // This is a type that showed up in an // elaborated-type-specifier inside the anonymous struct or // union, but which actually declares a type outside of the // anonymous struct or union. It's okay. } else if (auto *MemRecord = dyn_cast(Mem)) { if (!MemRecord->isAnonymousStructOrUnion() && MemRecord->getDeclName()) { // Visual C++ allows type definition in anonymous struct or union. if (getLangOpts().MicrosoftExt) Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type) << Record->isUnion(); else { // This is a nested type declaration. Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type) << Record->isUnion(); Invalid = true; } } else { // This is an anonymous type definition within another anonymous type. // This is a popular extension, provided by Plan9, MSVC and GCC, but // not part of standard C++. Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_anonymous_type) << Record->isUnion(); } } else if (isa(Mem)) { // Any access specifier is fine. } else if (isa(Mem)) { // In C++1z, static_assert declarations are also fine. } else { // We have something that isn't a non-static data // member. Complain about it. unsigned DK = diag::err_anonymous_record_bad_member; if (isa(Mem)) DK = diag::err_anonymous_record_with_type; else if (isa(Mem)) DK = diag::err_anonymous_record_with_function; else if (isa(Mem)) DK = diag::err_anonymous_record_with_static; // Visual C++ allows type definition in anonymous struct or union. if (getLangOpts().MicrosoftExt && DK == diag::err_anonymous_record_with_type) Diag(Mem->getLocation(), diag::ext_anonymous_record_with_type) << Record->isUnion(); else { Diag(Mem->getLocation(), DK) << Record->isUnion(); Invalid = true; } } } // C++11 [class.union]p8 (DR1460): // At most one variant member of a union may have a // brace-or-equal-initializer. if (cast(Record)->hasInClassInitializer() && Owner->isRecord()) checkDuplicateDefaultInit(*this, cast(Owner), cast(Record)); } if (!Record->isUnion() && !Owner->isRecord()) { Diag(Record->getLocation(), diag::err_anonymous_struct_not_member) << getLangOpts().CPlusPlus; Invalid = true; } // Mock up a declarator. Declarator Dc(DS, Declarator::MemberContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct/union"); // Create a declaration for this anonymous struct/union. NamedDecl *Anon = nullptr; if (RecordDecl *OwningClass = dyn_cast(Owner)) { Anon = FieldDecl::Create(Context, OwningClass, DS.getLocStart(), Record->getLocation(), /*IdentifierInfo=*/nullptr, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit); Anon->setAccess(AS); if (getLangOpts().CPlusPlus) FieldCollector->Add(cast(Anon)); } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS); if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(Record->getLocation(), diag::err_mutable_nonmember); Invalid = true; SC = SC_None; } Anon = VarDecl::Create(Context, Owner, DS.getLocStart(), Record->getLocation(), /*IdentifierInfo=*/nullptr, Context.getTypeDeclType(Record), TInfo, SC); // Default-initialize the implicit variable. This initialization will be // trivial in almost all cases, except if a union member has an in-class // initializer: // union { int n = 0; }; ActOnUninitializedDecl(Anon); } Anon->setImplicit(); // Mark this as an anonymous struct/union type. Record->setAnonymousStructOrUnion(true); // Add the anonymous struct/union object to the current // context. We'll be referencing this object when we refer to one of // its members. Owner->addDecl(Anon); // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. SmallVector Chain; Chain.push_back(Anon); if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, Chain)) Invalid = true; if (VarDecl *NewVD = dyn_cast(Anon)) { if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { Decl *ManglingContextDecl; if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext( NewVD->getDeclContext(), ManglingContextDecl)) { Context.setManglingNumber( NewVD, MCtx->getManglingNumber( NewVD, getMSManglingNumber(getLangOpts(), S))); Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD)); } } } if (Invalid) Anon->setInvalidDecl(); return Anon; } /// BuildMicrosoftCAnonymousStruct - Handle the declaration of an /// Microsoft C anonymous structure. /// Ref: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx /// Example: /// /// struct A { int a; }; /// struct B { struct A; int b; }; /// /// void foo() { /// B var; /// var.a = 3; /// } /// Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record) { assert(Record && "expected a record!"); // Mock up a declarator. Declarator Dc(DS, Declarator::TypeNameContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct"); auto *ParentDecl = cast(CurContext); QualType RecTy = Context.getTypeDeclType(Record); // Create a declaration for this anonymous struct. NamedDecl *Anon = FieldDecl::Create(Context, ParentDecl, DS.getLocStart(), DS.getLocStart(), /*IdentifierInfo=*/nullptr, RecTy, TInfo, /*BitWidth=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit); Anon->setImplicit(); // Add the anonymous struct object to the current context. CurContext->addDecl(Anon); // Inject the members of the anonymous struct into the current // context and into the identifier resolver chain for name lookup // purposes. SmallVector Chain; Chain.push_back(Anon); RecordDecl *RecordDef = Record->getDefinition(); if (RequireCompleteType(Anon->getLocation(), RecTy, diag::err_field_incomplete) || InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef, AS_none, Chain)) { Anon->setInvalidDecl(); ParentDecl->setInvalidDecl(); } return Anon; } /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. DeclarationNameInfo Sema::GetNameForDeclarator(Declarator &D) { return GetNameFromUnqualifiedId(D.getName()); } /// \brief Retrieves the declaration name from a parsed unqualified-id. DeclarationNameInfo Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { DeclarationNameInfo NameInfo; NameInfo.setLoc(Name.StartLocation); switch (Name.getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_Identifier: NameInfo.setName(Name.Identifier); NameInfo.setLoc(Name.StartLocation); return NameInfo; case UnqualifiedId::IK_DeductionGuideName: { // C++ [temp.deduct.guide]p3: // The simple-template-id shall name a class template specialization. // The template-name shall be the same identifier as the template-name // of the simple-template-id. // These together intend to imply that the template-name shall name a // class template. // FIXME: template struct X {}; // template using Y = X; // Y(int) -> Y; // satisfies these rules but does not name a class template. TemplateName TN = Name.TemplateName.get().get(); auto *Template = TN.getAsTemplateDecl(); if (!Template || !isa(Template)) { Diag(Name.StartLocation, diag::err_deduction_guide_name_not_class_template) << (int)getTemplateNameKindForDiagnostics(TN) << TN; if (Template) Diag(Template->getLocation(), diag::note_template_decl_here); return DeclarationNameInfo(); } NameInfo.setName( Context.DeclarationNames.getCXXDeductionGuideName(Template)); NameInfo.setLoc(Name.StartLocation); return NameInfo; } case UnqualifiedId::IK_OperatorFunctionId: NameInfo.setName(Context.DeclarationNames.getCXXOperatorName( Name.OperatorFunctionId.Operator)); NameInfo.setLoc(Name.StartLocation); NameInfo.getInfo().CXXOperatorName.BeginOpNameLoc = Name.OperatorFunctionId.SymbolLocations[0]; NameInfo.getInfo().CXXOperatorName.EndOpNameLoc = Name.EndLocation.getRawEncoding(); return NameInfo; case UnqualifiedId::IK_LiteralOperatorId: NameInfo.setName(Context.DeclarationNames.getCXXLiteralOperatorName( Name.Identifier)); NameInfo.setLoc(Name.StartLocation); NameInfo.setCXXLiteralOperatorNameLoc(Name.EndLocation); return NameInfo; case UnqualifiedId::IK_ConversionFunctionId: { TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(Name.ConversionFunctionId, &TInfo); if (Ty.isNull()) return DeclarationNameInfo(); NameInfo.setName(Context.DeclarationNames.getCXXConversionFunctionName( Context.getCanonicalType(Ty))); NameInfo.setLoc(Name.StartLocation); NameInfo.setNamedTypeInfo(TInfo); return NameInfo; } case UnqualifiedId::IK_ConstructorName: { TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(Name.ConstructorName, &TInfo); if (Ty.isNull()) return DeclarationNameInfo(); NameInfo.setName(Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(Ty))); NameInfo.setLoc(Name.StartLocation); NameInfo.setNamedTypeInfo(TInfo); return NameInfo; } case UnqualifiedId::IK_ConstructorTemplateId: { // In well-formed code, we can only have a constructor // template-id that refers to the current context, so go there // to find the actual type being constructed. CXXRecordDecl *CurClass = dyn_cast(CurContext); if (!CurClass || CurClass->getIdentifier() != Name.TemplateId->Name) return DeclarationNameInfo(); // Determine the type of the class being constructed. QualType CurClassType = Context.getTypeDeclType(CurClass); // FIXME: Check two things: that the template-id names the same type as // CurClassType, and that the template-id does not occur when the name // was qualified. NameInfo.setName(Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(CurClassType))); NameInfo.setLoc(Name.StartLocation); // FIXME: should we retrieve TypeSourceInfo? NameInfo.setNamedTypeInfo(nullptr); return NameInfo; } case UnqualifiedId::IK_DestructorName: { TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(Name.DestructorName, &TInfo); if (Ty.isNull()) return DeclarationNameInfo(); NameInfo.setName(Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(Ty))); NameInfo.setLoc(Name.StartLocation); NameInfo.setNamedTypeInfo(TInfo); return NameInfo; } case UnqualifiedId::IK_TemplateId: { TemplateName TName = Name.TemplateId->Template.get(); SourceLocation TNameLoc = Name.TemplateId->TemplateNameLoc; return Context.getNameForTemplate(TName, TNameLoc); } } // switch (Name.getKind()) llvm_unreachable("Unknown name kind"); } static QualType getCoreType(QualType Ty) { do { if (Ty->isPointerType() || Ty->isReferenceType()) Ty = Ty->getPointeeType(); else if (Ty->isArrayType()) Ty = Ty->castAsArrayTypeUnsafe()->getElementType(); else return Ty.withoutLocalFastQualifiers(); } while (true); } /// hasSimilarParameters - Determine whether the C++ functions Declaration /// and Definition have "nearly" matching parameters. This heuristic is /// used to improve diagnostics in the case where an out-of-line function /// definition doesn't match any declaration within the class or namespace. /// Also sets Params to the list of indices to the parameters that differ /// between the declaration and the definition. If hasSimilarParameters /// returns true and Params is empty, then all of the parameters match. static bool hasSimilarParameters(ASTContext &Context, FunctionDecl *Declaration, FunctionDecl *Definition, SmallVectorImpl &Params) { Params.clear(); if (Declaration->param_size() != Definition->param_size()) return false; for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) { QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType(); QualType DefParamTy = Definition->getParamDecl(Idx)->getType(); // The parameter types are identical if (Context.hasSameType(DefParamTy, DeclParamTy)) continue; QualType DeclParamBaseTy = getCoreType(DeclParamTy); QualType DefParamBaseTy = getCoreType(DefParamTy); const IdentifierInfo *DeclTyName = DeclParamBaseTy.getBaseTypeIdentifier(); const IdentifierInfo *DefTyName = DefParamBaseTy.getBaseTypeIdentifier(); if (Context.hasSameUnqualifiedType(DeclParamBaseTy, DefParamBaseTy) || (DeclTyName && DeclTyName == DefTyName)) Params.push_back(Idx); else // The two parameters aren't even close return false; } return true; } /// NeedsRebuildingInCurrentInstantiation - Checks whether the given /// declarator needs to be rebuilt in the current instantiation. /// Any bits of declarator which appear before the name are valid for /// consideration here. That's specifically the type in the decl spec /// and the base type in any member-pointer chunks. static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, DeclarationName Name) { // The types we specifically need to rebuild are: // - typenames, typeofs, and decltypes // - types which will become injected class names // Of course, we also need to rebuild any type referencing such a // type. It's safest to just say "dependent", but we call out a // few cases here. DeclSpec &DS = D.getMutableDeclSpec(); switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: case DeclSpec::TST_underlyingType: case DeclSpec::TST_atomic: { // Grab the type from the parser. TypeSourceInfo *TSI = nullptr; QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); if (T.isNull() || !T->isDependentType()) break; // Make sure there's a type source info. This isn't really much // of a waste; most dependent types should have type source info // attached already. if (!TSI) TSI = S.Context.getTrivialTypeSourceInfo(T, DS.getTypeSpecTypeLoc()); // Rebuild the type in the current instantiation. TSI = S.RebuildTypeInCurrentInstantiation(TSI, D.getIdentifierLoc(), Name); if (!TSI) return true; // Store the new type back in the decl spec. ParsedType LocType = S.CreateParsedType(TSI->getType(), TSI); DS.UpdateTypeRep(LocType); break; } case DeclSpec::TST_decltype: case DeclSpec::TST_typeofExpr: { Expr *E = DS.getRepAsExpr(); ExprResult Result = S.RebuildExprInCurrentInstantiation(E); if (Result.isInvalid()) return true; DS.UpdateExprRep(Result.get()); break; } default: // Nothing to do for these decl specs. break; } // It doesn't matter what order we do this in. for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { DeclaratorChunk &Chunk = D.getTypeObject(I); // The only type information in the declarator which can come // before the declaration name is the base type of a member // pointer. if (Chunk.Kind != DeclaratorChunk::MemberPointer) continue; // Rebuild the scope specifier in-place. CXXScopeSpec &SS = Chunk.Mem.Scope(); if (S.RebuildNestedNameSpecifierInCurrentInstantiation(SS)) return true; } return false; } Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { D.setFunctionDefinitionKind(FDK_Declaration); Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg()); if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() && Dcl && Dcl->getDeclContext()->isFileContext()) Dcl->setTopLevelDeclInObjCContainer(); if (getLangOpts().OpenCL) setCurrentOpenCLExtensionForDecl(Dcl); return Dcl; } /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: /// If T is the name of a class, then each of the following shall have a /// name different from T: /// - every static data member of class T; /// - every member function of class T /// - every member of class T that is itself a type; /// \returns true if the declaration name violates these rules. bool Sema::DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo NameInfo) { DeclarationName Name = NameInfo.getName(); CXXRecordDecl *Record = dyn_cast(DC); while (Record && Record->isAnonymousStructOrUnion()) Record = dyn_cast(Record->getParent()); if (Record && Record->getIdentifier() && Record->getDeclName() == Name) { Diag(NameInfo.getLoc(), diag::err_member_name_of_class) << Name; return true; } return false; } /// \brief Diagnose a declaration whose declarator-id has the given /// nested-name-specifier. /// /// \param SS The nested-name-specifier of the declarator-id. /// /// \param DC The declaration context to which the nested-name-specifier /// resolves. /// /// \param Name The name of the entity being declared. /// /// \param Loc The location of the name of the entity being declared. /// /// \returns true if we cannot safely recover from this error, false otherwise. bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, SourceLocation Loc) { DeclContext *Cur = CurContext; while (isa(Cur) || isa(Cur)) Cur = Cur->getParent(); // If the user provided a superfluous scope specifier that refers back to the // class in which the entity is already declared, diagnose and ignore it. // // class X { // void X::f(); // }; // // Note, it was once ill-formed to give redundant qualification in all // contexts, but that rule was removed by DR482. if (Cur->Equals(DC)) { if (Cur->isRecord()) { Diag(Loc, LangOpts.MicrosoftExt ? diag::warn_member_extra_qualification : diag::err_member_extra_qualification) << Name << FixItHint::CreateRemoval(SS.getRange()); SS.clear(); } else { Diag(Loc, diag::warn_namespace_member_extra_qualification) << Name; } return false; } // Check whether the qualifying scope encloses the scope of the original // declaration. if (!Cur->Encloses(DC)) { if (Cur->isRecord()) Diag(Loc, diag::err_member_qualification) << Name << SS.getRange(); else if (isa(DC)) Diag(Loc, diag::err_invalid_declarator_global_scope) << Name << SS.getRange(); else if (isa(Cur)) Diag(Loc, diag::err_invalid_declarator_in_function) << Name << SS.getRange(); else if (isa(Cur)) Diag(Loc, diag::err_invalid_declarator_in_block) << Name << SS.getRange(); else Diag(Loc, diag::err_invalid_declarator_scope) << Name << cast(Cur) << cast(DC) << SS.getRange(); return true; } if (Cur->isRecord()) { // Cannot qualify members within a class. Diag(Loc, diag::err_member_qualification) << Name << SS.getRange(); SS.clear(); // C++ constructors and destructors with incorrect scopes can break // our AST invariants by having the wrong underlying types. If // that's the case, then drop this declaration entirely. if ((Name.getNameKind() == DeclarationName::CXXConstructorName || Name.getNameKind() == DeclarationName::CXXDestructorName) && !Context.hasSameType(Name.getCXXNameType(), Context.getTypeDeclType(cast(Cur)))) return true; return false; } // C++11 [dcl.meaning]p1: // [...] "The nested-name-specifier of the qualified declarator-id shall // not begin with a decltype-specifer" NestedNameSpecifierLoc SpecLoc(SS.getScopeRep(), SS.location_data()); while (SpecLoc.getPrefix()) SpecLoc = SpecLoc.getPrefix(); if (dyn_cast_or_null( SpecLoc.getNestedNameSpecifier()->getAsType())) Diag(Loc, diag::err_decltype_in_declarator) << SpecLoc.getTypeLoc().getSourceRange(); return false; } NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists) { // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); // All of these full declarators require an identifier. If it doesn't have // one, the ParsedFreeStandingDeclSpec action should be used. if (D.isDecompositionDeclarator()) { return ActOnDecompositionDeclarator(S, D, TemplateParamLists); } else if (!Name) { if (!D.isInvalidType()) // Reject this if we think it is valid. Diag(D.getDeclSpec().getLocStart(), diag::err_declarator_need_ident) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); return nullptr; } else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType)) return nullptr; // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. while ((S->getFlags() & Scope::DeclScope) == 0 || (S->getFlags() & Scope::TemplateParamScope) != 0) S = S->getParent(); DeclContext *DC = CurContext; if (D.getCXXScopeSpec().isInvalid()) D.setInvalidType(); else if (D.getCXXScopeSpec().isSet()) { if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(), UPPC_DeclarationQualifier)) return nullptr; bool EnteringContext = !D.getDeclSpec().isFriendSpecified(); DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext); if (!DC || isa(DC)) { // If we could not compute the declaration context, it's because the // declaration context is dependent but does not refer to a class, // class template, or class template partial specialization. Complain // and return early, to avoid the coming semantic disaster. Diag(D.getIdentifierLoc(), diag::err_template_qualified_declarator_no_match) << D.getCXXScopeSpec().getScopeRep() << D.getCXXScopeSpec().getRange(); return nullptr; } bool IsDependentContext = DC->isDependentContext(); if (!IsDependentContext && RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) return nullptr; // If a class is incomplete, do not parse entities inside it. if (isa(DC) && !cast(DC)->hasDefinition()) { Diag(D.getIdentifierLoc(), diag::err_member_def_undefined_record) << Name << DC << D.getCXXScopeSpec().getRange(); return nullptr; } if (!D.getDeclSpec().isFriendSpecified()) { if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC, Name, D.getIdentifierLoc())) { if (DC->isRecord()) return nullptr; D.setInvalidType(); } } // Check whether we need to rebuild the type of the given // declaration in the current instantiation. if (EnteringContext && IsDependentContext && TemplateParamLists.size() != 0) { ContextRAII SavedContext(*this, DC); if (RebuildDeclaratorInCurrentInstantiation(*this, D, Name)) D.setInvalidType(); } } TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo)) // If this is a typedef, we'll end up spewing multiple diagnostics. // Just return early; it's safer. If this is a function, let the // "constructor cannot have a return type" diagnostic handle it. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) return nullptr; if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DeclarationType)) D.setInvalidType(); LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); // See if this is a redefinition of a variable in the same scope. if (!D.getCXXScopeSpec().isSet()) { bool IsLinkageLookup = false; bool CreateBuiltins = false; // If the declaration we're planning to build will be a function // or object with linkage, then look for another declaration with // linkage (C99 6.2.2p4-5 and C++ [basic.link]p6). // // If the declaration we're planning to build will be declared with // external linkage in the translation unit, create any builtin with // the same name. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) /* Do nothing*/; else if (CurContext->isFunctionOrMethod() && (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern || R->isFunctionType())) { IsLinkageLookup = true; CreateBuiltins = CurContext->getEnclosingNamespaceContext()->isTranslationUnit(); } else if (CurContext->getRedeclContext()->isTranslationUnit() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) CreateBuiltins = true; if (IsLinkageLookup) Previous.clear(LookupRedeclarationWithLinkage); LookupName(Previous, S, CreateBuiltins); } else { // Something like "int foo::x;" LookupQualifiedName(Previous, DC); // C++ [dcl.meaning]p1: // When the declarator-id is qualified, the declaration shall refer to a // previously declared member of the class or namespace to which the // qualifier refers (or, in the case of a namespace, of an element of the // inline namespace set of that namespace (7.3.1)) or to a specialization // thereof; [...] // // Note that we already checked the context above, and that we do not have // enough information to make sure that Previous contains the declaration // we want to match. For example, given: // // class X { // void f(); // void f(float); // }; // // void X::f(int) { } // ill-formed // // In this case, Previous will point to the overload set // containing the two f's declared in X, but neither of them // matches. // C++ [dcl.meaning]p1: // [...] the member shall not merely have been introduced by a // using-declaration in the scope of the class or namespace nominated by // the nested-name-specifier of the declarator-id. RemoveUsingDecls(Previous); } if (Previous.isSingleResult() && Previous.getFoundDecl()->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. if (!D.isInvalidType()) DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), Previous.getFoundDecl()); // Just pretend that we didn't see the previous declaration. Previous.clear(); } // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). if (Previous.isSingleTagDecl() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) Previous.clear(); // Check that there are no default arguments other than in the parameters // of a function declaration (C++ only). if (getLangOpts().CPlusPlus) CheckExtraCXXDefaultArguments(D); if (D.getDeclSpec().isConceptSpecified()) { // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be // applied only to the definition of a function template or variable // template, declared in namespace scope if (!TemplateParamLists.size()) { Diag(D.getDeclSpec().getConceptSpecLoc(), diag:: err_concept_wrong_decl_kind); return nullptr; } if (!DC->getRedeclContext()->isFileContext()) { Diag(D.getIdentifierLoc(), diag::err_concept_decls_may_only_appear_in_namespace_scope); return nullptr; } } NamedDecl *New; bool AddToScope = true; if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { if (TemplateParamLists.size()) { Diag(D.getIdentifierLoc(), diag::err_template_typedef); return nullptr; } New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous); } else if (R->isFunctionType()) { New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists, AddToScope); } else { New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists, AddToScope); } if (!New) return nullptr; // If this has an identifier and is not a function template specialization, // add it to the scope stack. if (New->getDeclName() && AddToScope) { // Only make a locally-scoped extern declaration visible if it is the first // declaration of this entity. Qualified lookup for such an entity should // only find this declaration if there is no visible declaration of it. bool AddToContext = !D.isRedeclaration() || !New->isLocalExternDecl(); PushOnScopeChains(New, S, AddToContext); if (!AddToContext) CurContext->addHiddenDecl(New); } if (isInOpenMPDeclareTargetContext()) checkDeclIsAllowedInOpenMPTarget(nullptr, New); return New; } /// Helper method to turn variable array types into constant array /// types in certain situations which would otherwise be errors (for /// GCC compatibility). static QualType TryToFixInvalidVariablyModifiedType(QualType T, ASTContext &Context, bool &SizeIsNegative, llvm::APSInt &Oversized) { // This method tries to turn a variable array into a constant // array even when the size isn't an ICE. This is necessary // for compatibility with code that depends on gcc's buggy // constant expression folding, like struct {char x[(int)(char*)2];} SizeIsNegative = false; Oversized = 0; if (T->isDependentType()) return QualType(); QualifierCollector Qs; const Type *Ty = Qs.strip(T); if (const PointerType* PTy = dyn_cast(Ty)) { QualType Pointee = PTy->getPointeeType(); QualType FixedType = TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative, Oversized); if (FixedType.isNull()) return FixedType; FixedType = Context.getPointerType(FixedType); return Qs.apply(Context, FixedType); } if (const ParenType* PTy = dyn_cast(Ty)) { QualType Inner = PTy->getInnerType(); QualType FixedType = TryToFixInvalidVariablyModifiedType(Inner, Context, SizeIsNegative, Oversized); if (FixedType.isNull()) return FixedType; FixedType = Context.getParenType(FixedType); return Qs.apply(Context, FixedType); } const VariableArrayType* VLATy = dyn_cast(T); if (!VLATy) return QualType(); // FIXME: We should probably handle this case if (VLATy->getElementType()->isVariablyModifiedType()) return QualType(); llvm::APSInt Res; if (!VLATy->getSizeExpr() || !VLATy->getSizeExpr()->EvaluateAsInt(Res, Context)) return QualType(); // Check whether the array size is negative. if (Res.isSigned() && Res.isNegative()) { SizeIsNegative = true; return QualType(); } // Check whether the array is too large to be addressed. unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, VLATy->getElementType(), Res); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { Oversized = Res; return QualType(); } return Context.getConstantArrayType(VLATy->getElementType(), Res, ArrayType::Normal, 0); } static void FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) { SrcTL = SrcTL.getUnqualifiedLoc(); DstTL = DstTL.getUnqualifiedLoc(); if (PointerTypeLoc SrcPTL = SrcTL.getAs()) { PointerTypeLoc DstPTL = DstTL.castAs(); FixInvalidVariablyModifiedTypeLoc(SrcPTL.getPointeeLoc(), DstPTL.getPointeeLoc()); DstPTL.setStarLoc(SrcPTL.getStarLoc()); return; } if (ParenTypeLoc SrcPTL = SrcTL.getAs()) { ParenTypeLoc DstPTL = DstTL.castAs(); FixInvalidVariablyModifiedTypeLoc(SrcPTL.getInnerLoc(), DstPTL.getInnerLoc()); DstPTL.setLParenLoc(SrcPTL.getLParenLoc()); DstPTL.setRParenLoc(SrcPTL.getRParenLoc()); return; } ArrayTypeLoc SrcATL = SrcTL.castAs(); ArrayTypeLoc DstATL = DstTL.castAs(); TypeLoc SrcElemTL = SrcATL.getElementLoc(); TypeLoc DstElemTL = DstATL.getElementLoc(); DstElemTL.initializeFullCopy(SrcElemTL); DstATL.setLBracketLoc(SrcATL.getLBracketLoc()); DstATL.setSizeExpr(SrcATL.getSizeExpr()); DstATL.setRBracketLoc(SrcATL.getRBracketLoc()); } /// Helper method to turn variable array types into constant array /// types in certain situations which would otherwise be errors (for /// GCC compatibility). static TypeSourceInfo* TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo, ASTContext &Context, bool &SizeIsNegative, llvm::APSInt &Oversized) { QualType FixedTy = TryToFixInvalidVariablyModifiedType(TInfo->getType(), Context, SizeIsNegative, Oversized); if (FixedTy.isNull()) return nullptr; TypeSourceInfo *FixedTInfo = Context.getTrivialTypeSourceInfo(FixedTy); FixInvalidVariablyModifiedTypeLoc(TInfo->getTypeLoc(), FixedTInfo->getTypeLoc()); return FixedTInfo; } /// \brief Register the given locally-scoped extern "C" declaration so /// that it can be found later for redeclarations. We include any extern "C" /// declaration that is not visible in the translation unit here, not just /// function-scope declarations. void Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) { if (!getLangOpts().CPlusPlus && ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit()) // Don't need to track declarations in the TU in C. return; // Note that we have a locally-scoped external with this name. Context.getExternCContextDecl()->makeDeclVisibleInContext(ND); } NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) { // FIXME: We can have multiple results via __attribute__((overloadable)). auto Result = Context.getExternCContextDecl()->lookup(Name); return Result.empty() ? nullptr : *Result.begin(); } /// \brief Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) { // FIXME: We should probably indicate the identifier in question to avoid // confusion for constructs like "virtual int a(), b;" if (DS.isVirtualSpecified()) Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function); if (DS.isExplicitSpecified()) Diag(DS.getExplicitSpecLoc(), diag::err_explicit_non_function); if (DS.isNoreturnSpecified()) Diag(DS.getNoreturnSpecLoc(), diag::err_noreturn_non_function); } NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) << D.getCXXScopeSpec().getRange(); D.setInvalidType(); // Pretend we didn't see the scope specifier. DC = CurContext; Previous.clear(); } DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (D.getDeclSpec().isInlineSpecified()) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) << getLangOpts().CPlusPlus1z; if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 1; if (D.getDeclSpec().isConceptSpecified()) Diag(D.getDeclSpec().getConceptSpecLoc(), diag::err_concept_wrong_decl_kind); if (D.getName().Kind != UnqualifiedId::IK_Identifier) { if (D.getName().Kind == UnqualifiedId::IK_DeductionGuideName) Diag(D.getName().StartLocation, diag::err_deduction_guide_invalid_specifier) << "typedef"; else Diag(D.getName().StartLocation, diag::err_typedef_not_identifier) << D.getName().getSourceRange(); return nullptr; } TypedefDecl *NewTD = ParseTypedefDecl(S, D, TInfo->getType(), TInfo); if (!NewTD) return nullptr; // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); CheckTypedefForVariablyModifiedType(S, NewTD); bool Redeclaration = D.isRedeclaration(); NamedDecl *ND = ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); D.setRedeclaration(Redeclaration); return ND; } void Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. // Note that variably modified types must be fixed before merging the decl so // that redeclarations will match. TypeSourceInfo *TInfo = NewTD->getTypeSourceInfo(); QualType T = TInfo->getType(); if (T->isVariablyModifiedType()) { getCurFunction()->setHasBranchProtectedScope(); if (S->getFnParent() == nullptr) { bool SizeIsNegative; llvm::APSInt Oversized; TypeSourceInfo *FixedTInfo = TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, SizeIsNegative, Oversized); if (FixedTInfo) { Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size); NewTD->setTypeSourceInfo(FixedTInfo); } else { if (SizeIsNegative) Diag(NewTD->getLocation(), diag::err_typecheck_negative_array_size); else if (T->isVariableArrayType()) Diag(NewTD->getLocation(), diag::err_vla_decl_in_file_scope); else if (Oversized.getBoolValue()) Diag(NewTD->getLocation(), diag::err_array_too_large) << Oversized.toString(10); else Diag(NewTD->getLocation(), diag::err_vm_decl_in_file_scope); NewTD->setInvalidDecl(); } } } } /// ActOnTypedefNameDecl - Perform semantic checking for a declaration which /// declares a typedef-name, either using the 'typedef' type specifier or via /// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. NamedDecl* Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, LookupResult &Previous, bool &Redeclaration) { // Find the shadowed declaration before filtering for scope. NamedDecl *ShadowedDecl = getShadowedDeclaration(NewTD, Previous); // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/false, /*AllowInlineNamespace*/false); filterNonConflictingPreviousTypedefDecls(*this, NewTD, Previous); if (!Previous.empty()) { Redeclaration = true; MergeTypedefNameDecl(S, NewTD, Previous); } if (ShadowedDecl && !Redeclaration) CheckShadow(NewTD, ShadowedDecl, Previous); // If this is the C FILE type, notify the AST context. if (IdentifierInfo *II = NewTD->getIdentifier()) if (!NewTD->isInvalidDecl() && NewTD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (II->isStr("FILE")) Context.setFILEDecl(NewTD); else if (II->isStr("jmp_buf")) Context.setjmp_bufDecl(NewTD); else if (II->isStr("sigjmp_buf")) Context.setsigjmp_bufDecl(NewTD); else if (II->isStr("ucontext_t")) Context.setucontext_tDecl(NewTD); } return NewTD; } /// \brief Determines whether the given declaration is an out-of-scope /// previous declaration. /// /// This routine should be invoked when name lookup has found a /// previous declaration (PrevDecl) that is not in the scope where a /// new declaration by the same name is being introduced. If the new /// declaration occurs in a local scope, previous declarations with /// linkage may still be considered previous declarations (C99 /// 6.2.2p4-5, C++ [basic.link]p6). /// /// \param PrevDecl the previous declaration found by name /// lookup /// /// \param DC the context in which the new declaration is being /// declared. /// /// \returns true if PrevDecl is an out-of-scope previous declaration /// for a new delcaration with the same name. static bool isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, ASTContext &Context) { if (!PrevDecl) return false; if (!PrevDecl->hasLinkage()) return false; if (Context.getLangOpts().CPlusPlus) { // C++ [basic.link]p6: // If there is a visible declaration of an entity with linkage // having the same name and type, ignoring entities declared // outside the innermost enclosing namespace scope, the block // scope declaration declares that same entity and receives the // linkage of the previous declaration. DeclContext *OuterContext = DC->getRedeclContext(); if (!OuterContext->isFunctionOrMethod()) // This rule only applies to block-scope declarations. return false; DeclContext *PrevOuterContext = PrevDecl->getDeclContext(); if (PrevOuterContext->isRecord()) // We found a member function: ignore it. return false; // Find the innermost enclosing namespace for the new and // previous declarations. OuterContext = OuterContext->getEnclosingNamespaceContext(); PrevOuterContext = PrevOuterContext->getEnclosingNamespaceContext(); // The previous declaration is in a different namespace, so it // isn't the same function. if (!OuterContext->Equals(PrevOuterContext)) return false; } return true; } static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) { CXXScopeSpec &SS = D.getCXXScopeSpec(); if (!SS.isSet()) return; DD->setQualifierInfo(SS.getWithLocInContext(DD->getASTContext())); } bool Sema::inferObjCARCLifetime(ValueDecl *decl) { QualType type = decl->getType(); Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime(); if (lifetime == Qualifiers::OCL_Autoreleasing) { // Various kinds of declaration aren't allowed to be __autoreleasing. unsigned kind = -1U; if (VarDecl *var = dyn_cast(decl)) { if (var->hasAttr()) kind = 0; // __block else if (!var->hasLocalStorage()) kind = 1; // global } else if (isa(decl)) { kind = 3; // ivar } else if (isa(decl)) { kind = 2; // field } if (kind != -1U) { Diag(decl->getLocation(), diag::err_arc_autoreleasing_var) << kind; } } else if (lifetime == Qualifiers::OCL_None) { // Try to infer lifetime. if (!type->isObjCLifetimeType()) return false; lifetime = type->getObjCARCImplicitLifetime(); type = Context.getLifetimeQualifiedType(type, lifetime); decl->setType(type); } if (VarDecl *var = dyn_cast(decl)) { // Thread-local variables cannot have lifetime. if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone && var->getTLSKind()) { Diag(var->getLocation(), diag::err_arc_thread_ownership) << var->getType(); return true; } } return false; } static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { // Ensure that an auto decl is deduced otherwise the checks below might cache // the wrong linkage. assert(S.ParsingInitForAutoVars.count(&ND) == 0); // 'weak' only applies to declarations with external linkage. if (WeakAttr *Attr = ND.getAttr()) { if (!ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_weak_static); ND.dropAttr(); } } if (WeakRefAttr *Attr = ND.getAttr()) { if (ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static); ND.dropAttr(); ND.dropAttr(); } } if (auto *VD = dyn_cast(&ND)) { if (VD->hasInit()) { if (const auto *Attr = VD->getAttr()) { assert(VD->isThisDeclarationADefinition() && !VD->isExternallyVisible() && "Broken AliasAttr handled late!"); S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD << 0; VD->dropAttr(); } } } // 'selectany' only applies to externally visible variable declarations. // It does not apply to functions. if (SelectAnyAttr *Attr = ND.getAttr()) { if (isa(ND) || !ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_selectany_non_extern_data); ND.dropAttr(); } } if (const InheritableAttr *Attr = getDLLAttr(&ND)) { // dll attributes require external linkage. Static locals may have external // linkage but still cannot be explicitly imported or exported. auto *VD = dyn_cast(&ND); if (!ND.isExternallyVisible() || (VD && VD->isStaticLocal())) { S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern) << &ND << Attr; ND.setInvalidDecl(); } } // Virtual functions cannot be marked as 'notail'. if (auto *Attr = ND.getAttr()) if (auto *MD = dyn_cast(&ND)) if (MD->isVirtual()) { S.Diag(ND.getLocation(), diag::err_invalid_attribute_on_virtual_function) << Attr; ND.dropAttr(); } } static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, NamedDecl *NewDecl, bool IsSpecialization, bool IsDefinition) { if (OldDecl->isInvalidDecl()) return; bool IsTemplate = false; if (TemplateDecl *OldTD = dyn_cast(OldDecl)) { OldDecl = OldTD->getTemplatedDecl(); IsTemplate = true; if (!IsSpecialization) IsDefinition = false; } if (TemplateDecl *NewTD = dyn_cast(NewDecl)) { NewDecl = NewTD->getTemplatedDecl(); IsTemplate = true; } if (!OldDecl || !NewDecl) return; const DLLImportAttr *OldImportAttr = OldDecl->getAttr(); const DLLExportAttr *OldExportAttr = OldDecl->getAttr(); const DLLImportAttr *NewImportAttr = NewDecl->getAttr(); const DLLExportAttr *NewExportAttr = NewDecl->getAttr(); // dllimport and dllexport are inheritable attributes so we have to exclude // inherited attribute instances. bool HasNewAttr = (NewImportAttr && !NewImportAttr->isInherited()) || (NewExportAttr && !NewExportAttr->isInherited()); // A redeclaration is not allowed to add a dllimport or dllexport attribute, // the only exception being explicit specializations. // Implicitly generated declarations are also excluded for now because there // is no other way to switch these to use dllimport or dllexport. bool AddsAttr = !(OldImportAttr || OldExportAttr) && HasNewAttr; if (AddsAttr && !IsSpecialization && !OldDecl->isImplicit()) { // Allow with a warning for free functions and global variables. bool JustWarn = false; if (!OldDecl->isCXXClassMember()) { auto *VD = dyn_cast(OldDecl); if (VD && !VD->getDescribedVarTemplate()) JustWarn = true; auto *FD = dyn_cast(OldDecl); if (FD && FD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) JustWarn = true; } // We cannot change a declaration that's been used because IR has already // been emitted. Dllimported functions will still work though (modulo // address equality) as they can use the thunk. if (OldDecl->isUsed()) if (!isa(OldDecl) || !NewImportAttr) JustWarn = false; unsigned DiagID = JustWarn ? diag::warn_attribute_dll_redeclaration : diag::err_attribute_dll_redeclaration; S.Diag(NewDecl->getLocation(), DiagID) << NewDecl << (NewImportAttr ? (const Attr *)NewImportAttr : NewExportAttr); S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); if (!JustWarn) { NewDecl->setInvalidDecl(); return; } } // A redeclaration is not allowed to drop a dllimport attribute, the only // exceptions being inline function definitions (except for function // templates), local extern declarations, qualified friend declarations or // special MSVC extension: in the last case, the declaration is treated as if // it were marked dllexport. bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false; bool IsMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft(); if (const auto *VD = dyn_cast(NewDecl)) { // Ignore static data because out-of-line definitions are diagnosed // separately. IsStaticDataMember = VD->isStaticDataMember(); IsDefinition = VD->isThisDeclarationADefinition(S.Context) != VarDecl::DeclarationOnly; } else if (const auto *FD = dyn_cast(NewDecl)) { IsInline = FD->isInlined(); IsQualifiedFriend = FD->getQualifier() && FD->getFriendObjectKind() == Decl::FOK_Declared; } if (OldImportAttr && !HasNewAttr && (!IsInline || (IsMicrosoft && IsTemplate)) && !IsStaticDataMember && !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) { if (IsMicrosoft && IsDefinition) { S.Diag(NewDecl->getLocation(), diag::warn_redeclaration_without_import_attribute) << NewDecl; S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); NewDecl->dropAttr(); NewDecl->addAttr(::new (S.Context) DLLExportAttr( NewImportAttr->getRange(), S.Context, NewImportAttr->getSpellingListIndex())); } else { S.Diag(NewDecl->getLocation(), diag::warn_redeclaration_without_attribute_prev_attribute_ignored) << NewDecl << OldImportAttr; S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); OldDecl->dropAttr(); NewDecl->dropAttr(); } } else if (IsInline && OldImportAttr && !IsMicrosoft) { // In MinGW, seeing a function declared inline drops the dllimport attribute. OldDecl->dropAttr(); NewDecl->dropAttr(); S.Diag(NewDecl->getLocation(), diag::warn_dllimport_dropped_from_inline_function) << NewDecl << OldImportAttr; } } /// Given that we are within the definition of the given function, /// will that definition behave like C99's 'inline', where the /// definition is discarded except for optimization purposes? static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) { // Try to avoid calling GetGVALinkageForFunction. // All cases of this require the 'inline' keyword. if (!FD->isInlined()) return false; // This is only possible in C++ with the gnu_inline attribute. if (S.getLangOpts().CPlusPlus && !FD->hasAttr()) return false; // Okay, go ahead and call the relatively-more-expensive function. return S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally; } /// Determine whether a variable is extern "C" prior to attaching /// an initializer. We can't just call isExternC() here, because that /// will also compute and cache whether the declaration is externally /// visible, which might change when we attach the initializer. /// /// This can only be used if the declaration is known to not be a /// redeclaration of an internal linkage declaration. /// /// For instance: /// /// auto x = []{}; /// /// Attaching the initializer here makes this declaration not externally /// visible, because its type has internal linkage. /// /// FIXME: This is a hack. template static bool isIncompleteDeclExternC(Sema &S, const T *D) { if (S.getLangOpts().CPlusPlus) { // In C++, the overloadable attribute negates the effects of extern "C". if (!D->isInExternCContext() || D->template hasAttr()) return false; // So do CUDA's host/device attributes. if (S.getLangOpts().CUDA && (D->template hasAttr() || D->template hasAttr())) return false; } return D->isExternC(); } static bool shouldConsiderLinkage(const VarDecl *VD) { const DeclContext *DC = VD->getDeclContext()->getRedeclContext(); if (DC->isFunctionOrMethod() || isa(DC)) return VD->hasExternalStorage(); if (DC->isFileContext()) return true; if (DC->isRecord()) return false; llvm_unreachable("Unexpected context"); } static bool shouldConsiderLinkage(const FunctionDecl *FD) { const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); if (DC->isFileContext() || DC->isFunctionOrMethod() || isa(DC)) return true; if (DC->isRecord()) return false; llvm_unreachable("Unexpected context"); } static bool hasParsedAttr(Scope *S, const AttributeList *AttrList, AttributeList::Kind Kind) { for (const AttributeList *L = AttrList; L; L = L->getNext()) if (L->getKind() == Kind) return true; return false; } static bool hasParsedAttr(Scope *S, const Declarator &PD, AttributeList::Kind Kind) { // Check decl attributes on the DeclSpec. if (hasParsedAttr(S, PD.getDeclSpec().getAttributes().getList(), Kind)) return true; // Walk the declarator structure, checking decl attributes that were in a type // position to the decl itself. for (unsigned I = 0, E = PD.getNumTypeObjects(); I != E; ++I) { if (hasParsedAttr(S, PD.getTypeObject(I).getAttrs(), Kind)) return true; } // Finally, check attributes on the decl itself. return hasParsedAttr(S, PD.getAttributes(), Kind); } /// Adjust the \c DeclContext for a function or variable that might be a /// function-local external declaration. bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) { if (!DC->isFunctionOrMethod()) return false; // If this is a local extern function or variable declared within a function // template, don't add it into the enclosing namespace scope until it is // instantiated; it might have a dependent type right now. if (DC->isDependentContext()) return true; // C++11 [basic.link]p7: // When a block scope declaration of an entity with linkage is not found to // refer to some other declaration, then that entity is a member of the // innermost enclosing namespace. // // Per C++11 [namespace.def]p6, the innermost enclosing namespace is a // semantically-enclosing namespace, not a lexically-enclosing one. while (!DC->isFileContext() && !isa(DC)) DC = DC->getParent(); return true; } /// \brief Returns true if given declaration has external C language linkage. static bool isDeclExternC(const Decl *D) { if (const auto *FD = dyn_cast(D)) return FD->isExternC(); if (const auto *VD = dyn_cast(D)) return VD->isExternC(); llvm_unreachable("Unknown type of decl!"); } NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope, ArrayRef Bindings) { QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); IdentifierInfo *II = Name.getAsIdentifierInfo(); if (D.isDecompositionDeclarator()) { AddToScope = false; // Take the name of the first declarator as our name for diagnostic // purposes. auto &Decomp = D.getDecompositionDeclarator(); if (!Decomp.bindings().empty()) { II = Decomp.bindings()[0].Name; Name = II; } } else if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) << Name; return nullptr; } if (getLangOpts().OpenCL) { // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument. // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function // argument. if (R->isImageType() || R->isPipeType()) { Diag(D.getIdentifierLoc(), diag::err_opencl_type_can_only_be_used_as_function_parameter) << R; D.setInvalidType(); return nullptr; } // OpenCL v1.2 s6.9.r: // The event type cannot be used to declare a program scope variable. // OpenCL v2.0 s6.9.q: // The clk_event_t and reserve_id_t types cannot be declared in program scope. if (NULL == S->getParent()) { if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) { Diag(D.getIdentifierLoc(), diag::err_invalid_type_for_program_scope_var) << R; D.setInvalidType(); return nullptr; } } // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. QualType NR = R; while (NR->isPointerType()) { if (NR->isFunctionPointerType()) { Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer_variable); D.setInvalidType(); break; } NR = NR->getPointeeType(); } if (!getOpenCLOptions().isEnabled("cl_khr_fp16")) { // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and // half array type (unless the cl_khr_fp16 extension is enabled). if (Context.getBaseElementType(R)->isHalfType()) { Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R; D.setInvalidType(); } } if (R->isSamplerT()) { // OpenCL v1.2 s6.9.b p4: // The sampler type cannot be used with the __local and __global address // space qualifiers. if (R.getAddressSpace() == LangAS::opencl_local || R.getAddressSpace() == LangAS::opencl_global) { Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace); } // OpenCL v1.2 s6.12.14.1: // A global sampler must be declared with either the constant address // space qualifier or with the const qualifier. if (DC->isTranslationUnit() && !(R.getAddressSpace() == LangAS::opencl_constant || R.isConstQualified())) { Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler); D.setInvalidType(); } } // OpenCL v1.2 s6.9.r: // The event type cannot be used with the __local, __constant and __global // address space qualifiers. if (R->isEventT()) { if (R.getAddressSpace()) { Diag(D.getLocStart(), diag::err_event_t_addr_space_qual); D.setInvalidType(); } } } DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); // dllimport globals without explicit storage class are treated as extern. We // have to change the storage class this early to get the right DeclContext. if (SC == SC_None && !DC->isRecord() && hasParsedAttr(S, D, AttributeList::AT_DLLImport) && !hasParsedAttr(S, D, AttributeList::AT_DLLExport)) SC = SC_Extern; DeclContext *OriginalDC = DC; bool IsLocalExternDecl = SC == SC_Extern && adjustContextForLocalExternDecl(DC); if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember); D.setInvalidType(); SC = SC_None; } if (getLangOpts().CPlusPlus11 && SCSpec == DeclSpec::SCS_register && !D.getAsmLabel() && !getSourceManager().isInSystemMacro( D.getDeclSpec().getStorageClassSpecLoc())) { // In C++11, the 'register' storage class specifier is deprecated. // Suppress the warning in system macros, it's used in macros in some // popular C system headers, such as in glibc's htonl() macro. Diag(D.getDeclSpec().getStorageClassSpecLoc(), getLangOpts().CPlusPlus1z ? diag::ext_register_storage_class : diag::warn_deprecated_register) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (!DC->isRecord() && S->getFnParent() == nullptr) { // C99 6.9p2: The storage-class specifiers auto and register shall not // appear in the declaration specifiers in an external declaration. // Global Register+Asm is a GNU extension we support. if (SC == SC_Auto || (SC == SC_Register && !D.getAsmLabel())) { Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope); D.setInvalidType(); } } bool IsMemberSpecialization = false; bool IsVariableTemplateSpecialization = false; bool IsPartialSpecialization = false; bool IsVariableTemplate = false; VarDecl *NewVD = nullptr; VarTemplateDecl *NewTemplate = nullptr; TemplateParameterList *TemplateParams = nullptr; if (!getLangOpts().CPlusPlus) { NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC); if (R->getContainedDeducedType()) ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType()) NewVD->setInvalidDecl(); } else { bool Invalid = false; if (DC->isRecord() && !CurContext->isRecord()) { // This is an out-of-line definition of a static data member. switch (SC) { case SC_None: break; case SC_Static: Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); break; case SC_Auto: case SC_Register: case SC_Extern: // [dcl.stc] p2: The auto or register specifiers shall be applied only // to names of variables declared in a block or to function parameters. // [dcl.stc] p6: The extern specifier cannot be used in the declaration // of class members Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_storage_class_for_static_member) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); break; case SC_PrivateExtern: llvm_unreachable("C storage class in c++!"); } } if (SC == SC_Static && CurContext->isRecord()) { if (const CXXRecordDecl *RD = dyn_cast(DC)) { if (RD->isLocalClass()) Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_local_class) << Name << RD->getDeclName(); // C++98 [class.union]p1: If a union contains a static data member, // the program is ill-formed. C++11 drops this restriction. if (RD->isUnion()) Diag(D.getIdentifierLoc(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_static_data_member_in_union : diag::ext_static_data_member_in_union) << Name; // We conservatively disallow static data members in anonymous structs. else if (!RD->getDeclName()) Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_anon_struct) << Name << RD->isUnion(); } } // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), D.getName().getKind() == UnqualifiedId::IK_TemplateId ? D.getName().TemplateId : nullptr, TemplateParamLists, /*never a friend*/ false, IsMemberSpecialization, Invalid); if (TemplateParams) { if (!TemplateParams->size() && D.getName().getKind() != UnqualifiedId::IK_TemplateId) { // There is an extraneous 'template<>' for this variable. Complain // about it, but allow the declaration of the variable. Diag(TemplateParams->getTemplateLoc(), diag::err_template_variable_noparams) << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); TemplateParams = nullptr; } else { if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { // This is an explicit specialization or a partial specialization. // FIXME: Check that we can declare a specialization here. IsVariableTemplateSpecialization = true; IsPartialSpecialization = TemplateParams->size() > 0; } else { // if (TemplateParams->size() > 0) // This is a template declaration. IsVariableTemplate = true; // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) return nullptr; // Only C++1y supports variable templates (N3651). Diag(D.getIdentifierLoc(), getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_variable_template : diag::ext_variable_template); } } } else { assert( (Invalid || D.getName().getKind() != UnqualifiedId::IK_TemplateId) && "should have a 'template<>' for this decl"); } if (IsVariableTemplateSpecialization) { SourceLocation TemplateKWLoc = TemplateParamLists.size() > 0 ? TemplateParamLists[0]->getTemplateLoc() : SourceLocation(); DeclResult Res = ActOnVarTemplateSpecialization( S, D, TInfo, TemplateKWLoc, TemplateParams, SC, IsPartialSpecialization); if (Res.isInvalid()) return nullptr; NewVD = cast(Res.get()); AddToScope = false; } else if (D.isDecompositionDeclarator()) { NewVD = DecompositionDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), R, TInfo, SC, Bindings); } else NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC); // If this is supposed to be a variable template, create it as such. if (IsVariableTemplate) { NewTemplate = VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name, TemplateParams, NewVD); NewVD->setDescribedVarTemplate(NewTemplate); } // If this decl has an auto type in need of deduction, make a note of the // Decl so we can diagnose uses of it in its own initializer. if (R->getContainedDeducedType()) ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType() || Invalid) { NewVD->setInvalidDecl(); if (NewTemplate) NewTemplate->setInvalidDecl(); } SetNestedNameSpecifier(NewVD, D); // If we have any template parameter lists that don't directly belong to // the variable (matching the scope specifier), store them. unsigned VDTemplateParamLists = TemplateParams ? 1 : 0; if (TemplateParamLists.size() > VDTemplateParamLists) NewVD->setTemplateParameterListsInfo( Context, TemplateParamLists.drop_back(VDTemplateParamLists)); if (D.getDeclSpec().isConstexprSpecified()) { NewVD->setConstexpr(true); // C++1z [dcl.spec.constexpr]p1: // A static data member declared with the constexpr specifier is // implicitly an inline variable. if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus1z) NewVD->setImplicitlyInline(); } if (D.getDeclSpec().isConceptSpecified()) { if (VarTemplateDecl *VTD = NewVD->getDescribedVarTemplate()) VTD->setConcept(); // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not // be declared with the thread_local, inline, friend, or constexpr // specifiers, [...] if (D.getDeclSpec().getThreadStorageClassSpec() == TSCS_thread_local) { Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_concept_decl_invalid_specifiers) << 0 << 0; NewVD->setInvalidDecl(true); } if (D.getDeclSpec().isConstexprSpecified()) { Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_concept_decl_invalid_specifiers) << 0 << 3; NewVD->setInvalidDecl(true); } // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be // applied only to the definition of a function template or variable // template, declared in namespace scope. if (IsVariableTemplateSpecialization) { Diag(D.getDeclSpec().getConceptSpecLoc(), diag::err_concept_specified_specialization) << (IsPartialSpecialization ? 2 : 1); } // C++ Concepts TS [dcl.spec.concept]p6: A variable concept has the // following restrictions: // - The declared type shall have the type bool. if (!Context.hasSameType(NewVD->getType(), Context.BoolTy) && !NewVD->isInvalidDecl()) { Diag(D.getIdentifierLoc(), diag::err_variable_concept_bool_decl); NewVD->setInvalidDecl(true); } } } if (D.getDeclSpec().isInlineSpecified()) { if (!getLangOpts().CPlusPlus) { Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) << 0; } else if (CurContext->isFunctionOrMethod()) { // 'inline' is not allowed on block scope variable declaration. Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_declaration_block_scope) << Name << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); } else { Diag(D.getDeclSpec().getInlineSpecLoc(), getLangOpts().CPlusPlus1z ? diag::warn_cxx14_compat_inline_variable : diag::ext_inline_variable); NewVD->setInlineSpecified(); } } // Set the lexical context. If the declarator has a C++ scope specifier, the // lexical context will be different from the semantic context. NewVD->setLexicalDeclContext(CurContext); if (NewTemplate) NewTemplate->setLexicalDeclContext(CurContext); if (IsLocalExternDecl) { if (D.isDecompositionDeclarator()) for (auto *B : Bindings) B->setLocalExternDecl(); else NewVD->setLocalExternDecl(); } bool EmitTLSUnsupportedError = false; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) { // C++11 [dcl.stc]p4: // When thread_local is applied to a variable of block scope the // storage-class-specifier static is implied if it does not appear // explicitly. // Core issue: 'static' is not implied if the variable is declared // 'extern'. if (NewVD->hasLocalStorage() && (SCSpec != DeclSpec::SCS_unspecified || TSCS != DeclSpec::TSCS_thread_local || !DC->isFunctionOrMethod())) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_non_global) << DeclSpec::getSpecifierName(TSCS); else if (!Context.getTargetInfo().isTLSSupported()) { if (getLangOpts().CUDA) { // Postpone error emission until we've collected attributes required to // figure out whether it's a host or device variable and whether the // error should be ignored. EmitTLSUnsupportedError = true; // We still need to mark the variable as TLS so it shows up in AST with // proper storage class for other tools to use even if we're not going // to emit any code for it. NewVD->setTSCSpec(TSCS); } else Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); } else NewVD->setTSCSpec(TSCS); } // C99 6.7.4p3 // An inline definition of a function with external linkage shall // not contain a definition of a modifiable object with static or // thread storage duration... // We only apply this when the function is required to be defined // elsewhere, i.e. when the function is not 'extern inline'. Note // that a local variable with thread storage duration still has to // be marked 'static'. Also note that it's possible to get these // semantics in C++ using __attribute__((gnu_inline)). if (SC == SC_Static && S->getFnParent() != nullptr && !NewVD->getType().isConstQualified()) { FunctionDecl *CurFD = getCurFunctionDecl(); if (CurFD && isFunctionDefinitionDiscarded(*this, CurFD)) { Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::warn_static_local_in_extern_inline); MaybeSuggestAddingStaticToDecl(CurFD); } } if (D.getDeclSpec().isModulePrivateSpecified()) { if (IsVariableTemplateSpecialization) Diag(NewVD->getLocation(), diag::err_module_private_specialization) << (IsPartialSpecialization ? 1 : 0) << FixItHint::CreateRemoval( D.getDeclSpec().getModulePrivateSpecLoc()); else if (IsMemberSpecialization) Diag(NewVD->getLocation(), diag::err_module_private_specialization) << 2 << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); else if (NewVD->hasLocalStorage()) Diag(NewVD->getLocation(), diag::err_module_private_local) << 0 << NewVD->getDeclName() << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); else { NewVD->setModulePrivate(); if (NewTemplate) NewTemplate->setModulePrivate(); for (auto *B : Bindings) B->setModulePrivate(); } } // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); if (getLangOpts().CUDA) { if (EmitTLSUnsupportedError && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); // CUDA B.2.5: "__shared__ and __constant__ variables have implied static // storage [duration]." if (SC == SC_None && S->getFnParent() != nullptr && (NewVD->hasAttr() || NewVD->hasAttr())) { NewVD->setStorageClass(SC_Static); } } // Ensure that dllimport globals without explicit storage class are treated as // extern. The storage class is set above using parsed attributes. Now we can // check the VarDecl itself. assert(!NewVD->hasAttr() || NewVD->getAttr()->isInherited() || NewVD->isStaticDataMember() || NewVD->getStorageClass() != SC_None); // In auto-retain/release, infer strong retension for variables of // retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewVD)) NewVD->setInvalidDecl(); // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*)D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); StringRef Label = SE->getString(); if (S->getFnParent() != nullptr) { switch (SC) { case SC_None: case SC_Auto: Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; break; case SC_Register: // Local Named register if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; break; case SC_Static: case SC_Extern: case SC_PrivateExtern: break; } } else if (SC == SC_Register) { // Global Named register if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { const auto &TI = Context.getTargetInfo(); bool HasSizeMismatch; if (!TI.isValidGCCRegisterName(Label)) Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; else if (!TI.validateGlobalRegisterVariable(Label, Context.getTypeSize(R), HasSizeMismatch)) Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; else if (HasSizeMismatch) Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; } if (!R->isIntegralType(Context) && !R->isPointerType()) { Diag(D.getLocStart(), diag::err_asm_bad_register_type); NewVD->setInvalidDecl(true); } } NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, Label, 0)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::iterator I = ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); if (I != ExtnameUndeclaredIdentifiers.end()) { if (isDeclExternC(NewVD)) { NewVD->addAttr(I->second); ExtnameUndeclaredIdentifiers.erase(I); } else Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) << /*Variable*/1 << NewVD; } } // Find the shadowed declaration before filtering for scope. NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty() ? getShadowedDeclaration(NewVD, Previous) : nullptr; // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewVD), D.getCXXScopeSpec().isNotEmpty() || IsMemberSpecialization || IsVariableTemplateSpecialization); // Check whether the previous declaration is in the same block scope. This // affects whether we merge types with it, per C++11 [dcl.array]p3. if (getLangOpts().CPlusPlus && NewVD->isLocalVarDecl() && NewVD->hasExternalStorage()) NewVD->setPreviousDeclInSameBlockScope( Previous.isSingleResult() && !Previous.isShadowed() && isDeclInScope(Previous.getFoundDecl(), OriginalDC, S, false)); if (!getLangOpts().CPlusPlus) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); } else { // If this is an explicit specialization of a static data member, check it. if (IsMemberSpecialization && !NewVD->isInvalidDecl() && CheckMemberSpecialization(NewVD, Previous)) NewVD->setInvalidDecl(); // Merge the decl with the existing one if appropriate. if (!Previous.empty()) { if (Previous.isSingleResult() && isa(Previous.getFoundDecl()) && D.getCXXScopeSpec().isSet()) { // The user tried to define a non-static data member // out-of-line (C++ [dcl.meaning]p1). Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) << D.getCXXScopeSpec().getRange(); Previous.clear(); NewVD->setInvalidDecl(); } } else if (D.getCXXScopeSpec().isSet()) { // No previous declaration in the qualifying scope. Diag(D.getIdentifierLoc(), diag::err_no_member) << Name << computeDeclContext(D.getCXXScopeSpec(), true) << D.getCXXScopeSpec().getRange(); NewVD->setInvalidDecl(); } if (!IsVariableTemplateSpecialization) D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...] // an explicit specialization (14.8.3) or a partial specialization of a // concept definition. if (IsVariableTemplateSpecialization && !D.getDeclSpec().isConceptSpecified() && !Previous.empty() && Previous.isSingleResult()) { NamedDecl *PreviousDecl = Previous.getFoundDecl(); if (VarTemplateDecl *VarTmpl = dyn_cast(PreviousDecl)) { if (VarTmpl->isConcept()) { Diag(NewVD->getLocation(), diag::err_concept_specialized) << 1 /*variable*/ << (IsPartialSpecialization ? 2 /*partially specialized*/ : 1 /*explicitly specialized*/); Diag(VarTmpl->getLocation(), diag::note_previous_declaration); NewVD->setInvalidDecl(); } } } if (NewTemplate) { VarTemplateDecl *PrevVarTemplate = NewVD->getPreviousDecl() ? NewVD->getPreviousDecl()->getDescribedVarTemplate() : nullptr; // Check the template parameter list of this declaration, possibly // merging in the template parameter list from the previous variable // template declaration. if (CheckTemplateParameterList( TemplateParams, PrevVarTemplate ? PrevVarTemplate->getTemplateParameters() : nullptr, (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && DC->isDependentContext()) ? TPC_ClassTemplateMember : TPC_VarTemplate)) NewVD->setInvalidDecl(); // If we are providing an explicit specialization of a static variable // template, make a note of that. if (PrevVarTemplate && PrevVarTemplate->getInstantiatedFromMemberTemplate()) PrevVarTemplate->setMemberSpecialization(); } } // Diagnose shadowed variables iff this isn't a redeclaration. if (ShadowedDecl && !D.isRedeclaration()) CheckShadow(NewVD, ShadowedDecl, Previous); ProcessPragmaWeak(S, NewVD); // If this is the first declaration of an extern C variable, update // the map of such variables. if (NewVD->isFirstDecl() && !NewVD->isInvalidDecl() && isIncompleteDeclExternC(*this, NewVD)) RegisterLocallyScopedExternCDecl(NewVD, S); if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { Decl *ManglingContextDecl; if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext( NewVD->getDeclContext(), ManglingContextDecl)) { Context.setManglingNumber( NewVD, MCtx->getManglingNumber( NewVD, getMSManglingNumber(getLangOpts(), S))); Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD)); } } // Special handling of variable named 'main'. if (Name.getAsIdentifierInfo() && Name.getAsIdentifierInfo()->isStr("main") && NewVD->getDeclContext()->getRedeclContext()->isTranslationUnit() && !getLangOpts().Freestanding && !NewVD->getDescribedVarTemplate()) { // C++ [basic.start.main]p3 // A program that declares a variable main at global scope is ill-formed. if (getLangOpts().CPlusPlus) Diag(D.getLocStart(), diag::err_main_global_variable); // In C, and external-linkage variable named main results in undefined // behavior. else if (NewVD->hasExternalFormalLinkage()) Diag(D.getLocStart(), diag::warn_main_redefined); } if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast(Previous.getRepresentativeDecl()), NewVD, IsMemberSpecialization, D.isFunctionDefinition()); } if (NewTemplate) { if (NewVD->isInvalidDecl()) NewTemplate->setInvalidDecl(); ActOnDocumentableDecl(NewTemplate); return NewTemplate; } if (IsMemberSpecialization && !NewVD->isInvalidDecl()) CompleteMemberSpecialization(NewVD, Previous); return NewVD; } /// Enum describing the %select options in diag::warn_decl_shadow. enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field, SDK_Typedef, SDK_Using }; /// Determine what kind of declaration we're shadowing. static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl, const DeclContext *OldDC) { if (isa(ShadowedDecl)) return SDK_Using; else if (isa(ShadowedDecl)) return SDK_Typedef; else if (isa(OldDC)) return isa(ShadowedDecl) ? SDK_Field : SDK_StaticMember; return OldDC->isFileContext() ? SDK_Global : SDK_Local; } /// Return the location of the capture if the given lambda captures the given /// variable \p VD, or an invalid source location otherwise. static SourceLocation getCaptureLocation(const LambdaScopeInfo *LSI, const VarDecl *VD) { for (const LambdaScopeInfo::Capture &Capture : LSI->Captures) { if (Capture.isVariableCapture() && Capture.getVariable() == VD) return Capture.getLocation(); } return SourceLocation(); } static bool shouldWarnIfShadowedDecl(const DiagnosticsEngine &Diags, const LookupResult &R) { // Only diagnose if we're shadowing an unambiguous field or variable. if (R.getResultKind() != LookupResult::Found) return false; // Return false if warning is ignored. return !Diags.isIgnored(diag::warn_decl_shadow, R.getNameLoc()); } /// \brief Return the declaration shadowed by the given variable \p D, or null /// if it doesn't shadow any declaration or shadowing warnings are disabled. NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D, const LookupResult &R) { if (!shouldWarnIfShadowedDecl(Diags, R)) return nullptr; // Don't diagnose declarations at file scope. if (D->hasGlobalStorage()) return nullptr; NamedDecl *ShadowedDecl = R.getFoundDecl(); return isa(ShadowedDecl) || isa(ShadowedDecl) ? ShadowedDecl : nullptr; } /// \brief Return the declaration shadowed by the given typedef \p D, or null /// if it doesn't shadow any declaration or shadowing warnings are disabled. NamedDecl *Sema::getShadowedDeclaration(const TypedefNameDecl *D, const LookupResult &R) { // Don't warn if typedef declaration is part of a class if (D->getDeclContext()->isRecord()) return nullptr; if (!shouldWarnIfShadowedDecl(Diags, R)) return nullptr; NamedDecl *ShadowedDecl = R.getFoundDecl(); return isa(ShadowedDecl) ? ShadowedDecl : nullptr; } /// \brief Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// /// This method is called whenever a VarDecl is added to a "useful" /// scope. /// /// \param ShadowedDecl the declaration that is shadowed by the given variable /// \param R the lookup of the name /// void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R) { DeclContext *NewDC = D->getDeclContext(); if (FieldDecl *FD = dyn_cast(ShadowedDecl)) { // Fields are not shadowed by variables in C++ static methods. if (CXXMethodDecl *MD = dyn_cast(NewDC)) if (MD->isStatic()) return; // Fields shadowed by constructor parameters are a special case. Usually // the constructor initializes the field with the parameter. if (isa(NewDC)) if (const auto PVD = dyn_cast(D)) { // Remember that this was shadowed so we can either warn about its // modification or its existence depending on warning settings. ShadowingDecls.insert({PVD->getCanonicalDecl(), FD}); return; } } if (VarDecl *shadowedVar = dyn_cast(ShadowedDecl)) if (shadowedVar->isExternC()) { // For shadowing external vars, make sure that we point to the global // declaration, not a locally scoped extern declaration. for (auto I : shadowedVar->redecls()) if (I->isFileVarDecl()) { ShadowedDecl = I; break; } } DeclContext *OldDC = ShadowedDecl->getDeclContext(); unsigned WarningDiag = diag::warn_decl_shadow; SourceLocation CaptureLoc; if (isa(D) && isa(ShadowedDecl) && NewDC && isa(NewDC)) { if (const auto *RD = dyn_cast(NewDC->getParent())) { if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) { if (RD->getLambdaCaptureDefault() == LCD_None) { // Try to avoid warnings for lambdas with an explicit capture list. const auto *LSI = cast(getCurFunction()); // Warn only when the lambda captures the shadowed decl explicitly. CaptureLoc = getCaptureLocation(LSI, cast(ShadowedDecl)); if (CaptureLoc.isInvalid()) WarningDiag = diag::warn_decl_shadow_uncaptured_local; } else { // Remember that this was shadowed so we can avoid the warning if the // shadowed decl isn't captured and the warning settings allow it. cast(getCurFunction()) ->ShadowingDecls.push_back( {cast(D), cast(ShadowedDecl)}); return; } } } } // Only warn about certain kinds of shadowing for class members. if (NewDC && NewDC->isRecord()) { // In particular, don't warn about shadowing non-class members. if (!OldDC->isRecord()) return; // TODO: should we warn about static data members shadowing // static data members from base classes? // TODO: don't diagnose for inaccessible shadowed members. // This is hard to do perfectly because we might friend the // shadowing context, but that's just a false negative. } DeclarationName Name = R.getLookupName(); // Emit warning and note. if (getSourceManager().isInSystemMacro(R.getNameLoc())) return; ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC); Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC; if (!CaptureLoc.isInvalid()) Diag(CaptureLoc, diag::note_var_explicitly_captured_here) << Name << /*explicitly*/ 1; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } /// Diagnose shadowing for variables shadowed in the lambda record \p LambdaRD /// when these variables are captured by the lambda. void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) { for (const auto &Shadow : LSI->ShadowingDecls) { const VarDecl *ShadowedDecl = Shadow.ShadowedDecl; // Try to avoid the warning when the shadowed decl isn't captured. SourceLocation CaptureLoc = getCaptureLocation(LSI, ShadowedDecl); const DeclContext *OldDC = ShadowedDecl->getDeclContext(); Diag(Shadow.VD->getLocation(), CaptureLoc.isInvalid() ? diag::warn_decl_shadow_uncaptured_local : diag::warn_decl_shadow) << Shadow.VD->getDeclName() << computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC; if (!CaptureLoc.isInvalid()) Diag(CaptureLoc, diag::note_var_explicitly_captured_here) << Shadow.VD->getDeclName() << /*explicitly*/ 0; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } } /// \brief Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { if (Diags.isIgnored(diag::warn_decl_shadow, D->getLocation())) return; LookupResult R(*this, D->getDeclName(), D->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); LookupName(R, S); if (NamedDecl *ShadowedDecl = getShadowedDeclaration(D, R)) CheckShadow(D, ShadowedDecl, R); } /// Check if 'E', which is an expression that is about to be modified, refers /// to a constructor parameter that shadows a field. void Sema::CheckShadowingDeclModification(Expr *E, SourceLocation Loc) { // Quickly ignore expressions that can't be shadowing ctor parameters. if (!getLangOpts().CPlusPlus || ShadowingDecls.empty()) return; E = E->IgnoreParenImpCasts(); auto *DRE = dyn_cast(E); if (!DRE) return; const NamedDecl *D = cast(DRE->getDecl()->getCanonicalDecl()); auto I = ShadowingDecls.find(D); if (I == ShadowingDecls.end()) return; const NamedDecl *ShadowedDecl = I->second; const DeclContext *OldDC = ShadowedDecl->getDeclContext(); Diag(Loc, diag::warn_modifying_shadowing_decl) << D << OldDC; Diag(D->getLocation(), diag::note_var_declared_here) << D; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); // Avoid issuing multiple warnings about the same decl. ShadowingDecls.erase(I); } /// Check for conflict between this global or extern "C" declaration and /// previous global or extern "C" declarations. This is only used in C++. template static bool checkGlobalOrExternCConflict( Sema &S, const T *ND, bool IsGlobal, LookupResult &Previous) { assert(S.getLangOpts().CPlusPlus && "only C++ has extern \"C\""); NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName()); if (!Prev && IsGlobal && !isIncompleteDeclExternC(S, ND)) { // The common case: this global doesn't conflict with any extern "C" // declaration. return false; } if (Prev) { if (!IsGlobal || isIncompleteDeclExternC(S, ND)) { // Both the old and new declarations have C language linkage. This is a // redeclaration. Previous.clear(); Previous.addDecl(Prev); return true; } // This is a global, non-extern "C" declaration, and there is a previous // non-global extern "C" declaration. Diagnose if this is a variable // declaration. if (!isa(ND)) return false; } else { // The declaration is extern "C". Check for any declaration in the // translation unit which might conflict. if (IsGlobal) { // We have already performed the lookup into the translation unit. IsGlobal = false; for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) { if (isa(*I)) { Prev = *I; break; } } } else { DeclContext::lookup_result R = S.Context.getTranslationUnitDecl()->lookup(ND->getDeclName()); for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (isa(*I)) { Prev = *I; break; } // FIXME: If we have any other entity with this name in global scope, // the declaration is ill-formed, but that is a defect: it breaks the // 'stat' hack, for instance. Only variables can have mangled name // clashes with extern "C" declarations, so only they deserve a // diagnostic. } } if (!Prev) return false; } // Use the first declaration's location to ensure we point at something which // is lexically inside an extern "C" linkage-spec. assert(Prev && "should have found a previous declaration to diagnose"); if (FunctionDecl *FD = dyn_cast(Prev)) Prev = FD->getFirstDecl(); else Prev = cast(Prev)->getFirstDecl(); S.Diag(ND->getLocation(), diag::err_extern_c_global_conflict) << IsGlobal << ND; S.Diag(Prev->getLocation(), diag::note_extern_c_global_conflict) << IsGlobal; return false; } /// Apply special rules for handling extern "C" declarations. Returns \c true /// if we have found that this is a redeclaration of some prior entity. /// /// Per C++ [dcl.link]p6: /// Two declarations [for a function or variable] with C language linkage /// with the same name that appear in different scopes refer to the same /// [entity]. An entity with C language linkage shall not be declared with /// the same name as an entity in global scope. template static bool checkForConflictWithNonVisibleExternC(Sema &S, const T *ND, LookupResult &Previous) { if (!S.getLangOpts().CPlusPlus) { // In C, when declaring a global variable, look for a corresponding 'extern' // variable declared in function scope. We don't need this in C++, because // we find local extern decls in the surrounding file-scope DeclContext. if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) { Previous.clear(); Previous.addDecl(Prev); return true; } } return false; } // A declaration in the translation unit can conflict with an extern "C" // declaration. if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/true, Previous); // An extern "C" declaration can conflict with a declaration in the // translation unit or can be a redeclaration of an extern "C" declaration // in another scope. if (isIncompleteDeclExternC(S,ND)) return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/false, Previous); // Neither global nor extern "C": nothing to do. return false; } void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) return; TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo(); QualType T = TInfo->getType(); // Defer checking an 'auto' type until its initializer is attached. if (T->isUndeducedType()) return; if (NewVD->hasAttrs()) CheckAlignasUnderalignment(NewVD); if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object) << FixItHint::CreateInsertion(NewVD->getLocation(), "*"); T = Context.getObjCObjectPointerType(T); NewVD->setType(T); } // Emit an error if an address space was applied to decl with local storage. // This includes arrays of objects with address space qualifiers, but not // automatic variables that point to other address spaces. // ISO/IEC TR 18037 S5.1.2 if (!getLangOpts().OpenCL && NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); NewVD->setInvalidDecl(); return; } // OpenCL v1.2 s6.8 - The static qualifier is valid only in program // scope. if (getLangOpts().OpenCLVersion == 120 && !getOpenCLOptions().isEnabled("cl_clang_storage_class_specifiers") && NewVD->isStaticLocal()) { Diag(NewVD->getLocation(), diag::err_static_function_scope); NewVD->setInvalidDecl(); return; } if (getLangOpts().OpenCL) { // OpenCL v2.0 s6.12.5 - The __block storage type is not supported. if (NewVD->hasAttr()) { Diag(NewVD->getLocation(), diag::err_opencl_block_storage_type); return; } if (T->isBlockPointerType()) { // OpenCL v2.0 s6.12.5 - Any block declaration must be const qualified and // can't use 'extern' storage class. if (!T.isConstQualified()) { Diag(NewVD->getLocation(), diag::err_opencl_invalid_block_declaration) << 0 /*const*/; NewVD->setInvalidDecl(); return; } if (NewVD->hasExternalStorage()) { Diag(NewVD->getLocation(), diag::err_opencl_extern_block_declaration); NewVD->setInvalidDecl(); return; } } // OpenCL v1.2 s6.5 - All program scope variables must be declared in the // __constant address space. // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static // variables inside a function can also be declared in the global // address space. if (NewVD->isFileVarDecl() || NewVD->isStaticLocal() || NewVD->hasExternalStorage()) { if (!T->isSamplerT() && !(T.getAddressSpace() == LangAS::opencl_constant || (T.getAddressSpace() == LangAS::opencl_global && getLangOpts().OpenCLVersion == 200))) { int Scope = NewVD->isStaticLocal() | NewVD->hasExternalStorage() << 1; if (getLangOpts().OpenCLVersion == 200) Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space) << Scope << "global or constant"; else Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space) << Scope << "constant"; NewVD->setInvalidDecl(); return; } } else { if (T.getAddressSpace() == LangAS::opencl_global) { Diag(NewVD->getLocation(), diag::err_opencl_function_variable) << 1 /*is any function*/ << "global"; NewVD->setInvalidDecl(); return; } // OpenCL v1.1 s6.5.2 and s6.5.3 no local or constant variables // in functions. if (T.getAddressSpace() == LangAS::opencl_constant || T.getAddressSpace() == LangAS::opencl_local) { FunctionDecl *FD = getCurFunctionDecl(); if (FD && !FD->hasAttr()) { if (T.getAddressSpace() == LangAS::opencl_constant) Diag(NewVD->getLocation(), diag::err_opencl_function_variable) << 0 /*non-kernel only*/ << "constant"; else Diag(NewVD->getLocation(), diag::err_opencl_function_variable) << 0 /*non-kernel only*/ << "local"; NewVD->setInvalidDecl(); return; } } } } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() && !NewVD->hasAttr()) { if (getLangOpts().getGC() != LangOptions::NonGC) Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); else { assert(!getLangOpts().ObjCAutoRefCount); Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); } } bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr() || NewVD->hasAttr()) getCurFunction()->setHasBranchProtectedScope(); if ((isVM && NewVD->hasLinkage()) || (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { bool SizeIsNegative; llvm::APSInt Oversized; TypeSourceInfo *FixedTInfo = TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, SizeIsNegative, Oversized); if (!FixedTInfo && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); // FIXME: This won't give the correct result for // int a[10][n]; SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange(); if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope) << SizeRange; else if (NewVD->isStaticLocal()) Diag(NewVD->getLocation(), diag::err_vla_decl_has_static_storage) << SizeRange; else Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) << SizeRange; NewVD->setInvalidDecl(); return; } if (!FixedTInfo) { if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); else Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); NewVD->setInvalidDecl(); return; } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); NewVD->setType(FixedTInfo->getType()); NewVD->setTypeSourceInfo(FixedTInfo); } if (T->isVoidType()) { // C++98 [dcl.stc]p5: The extern specifier can be applied only to the names // of objects and functions. if (NewVD->isThisDeclarationADefinition() || getLangOpts().CPlusPlus) { Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) << T; NewVD->setInvalidDecl(); return; } } if (!NewVD->hasLocalStorage() && NewVD->hasAttr()) { Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); NewVD->setInvalidDecl(); return; } if (isVM && NewVD->hasAttr()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); NewVD->setInvalidDecl(); return; } if (NewVD->isConstexpr() && !T->isDependentType() && RequireLiteralType(NewVD->getLocation(), T, diag::err_constexpr_var_non_literal)) { NewVD->setInvalidDecl(); return; } } /// \brief Perform semantic checking on a newly-created variable /// declaration. /// /// This routine performs all of the type-checking required for a /// variable declaration once it has been built. It is used both to /// check variables after they have been parsed and their declarators /// have been translated into a declaration, and to check variables /// that have been instantiated from a template. /// /// Sets NewVD->isInvalidDecl() if an error was encountered. /// /// Returns true if the variable declaration is a redeclaration. bool Sema::CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous) { CheckVariableDeclarationType(NewVD); // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) return false; // If we did not find anything by this name, look for a non-visible // extern "C" declaration with the same name. if (Previous.empty() && checkForConflictWithNonVisibleExternC(*this, NewVD, Previous)) Previous.setShadowed(); if (!Previous.empty()) { MergeVarDecl(NewVD, Previous); return true; } return false; } namespace { struct FindOverriddenMethod { Sema *S; CXXMethodDecl *Method; /// Member lookup function that determines whether a given C++ /// method overrides a method in a base class, to be used with /// CXXRecordDecl::lookupInBases(). bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); DeclarationName Name = Method->getDeclName(); // FIXME: Do we care about other names here too? if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // We really want to find the base class destructor here. QualType T = S->Context.getTypeDeclType(BaseRecord); CanQualType CT = S->Context.getCanonicalType(T); Name = S->Context.DeclarationNames.getCXXDestructorName(CT); } for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); Path.Decls = Path.Decls.slice(1)) { NamedDecl *D = Path.Decls.front(); if (CXXMethodDecl *MD = dyn_cast(D)) { if (MD->isVirtual() && !S->IsOverload(Method, MD, false)) return true; } } return false; } }; enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted }; } // end anonymous namespace /// \brief Report an error regarding overriding, along with any relevant /// overriden methods. /// /// \param DiagID the primary error to report. /// \param MD the overriding method. /// \param OEK which overrides to include as notes. static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD, OverrideErrorKind OEK = OEK_All) { S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { // This check (& the OEK parameter) could be replaced by a predicate, but // without lambdas that would be overkill. This is still nicer than writing // out the diag loop 3 times. if ((OEK == OEK_All) || (OEK == OEK_NonDeleted && !(*I)->isDeleted()) || (OEK == OEK_Deleted && (*I)->isDeleted())) S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function); } } /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { // Look for methods in base classes that this method might override. CXXBasePaths Paths; FindOverriddenMethod FOM; FOM.Method = MD; FOM.S = this; bool hasDeletedOverridenMethods = false; bool hasNonDeletedOverridenMethods = false; bool AddedAny = false; if (DC->lookupInBases(FOM, Paths)) { for (auto *I : Paths.found_decls()) { if (CXXMethodDecl *OldMD = dyn_cast(I)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionAttributes(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { hasDeletedOverridenMethods |= OldMD->isDeleted(); hasNonDeletedOverridenMethods |= !OldMD->isDeleted(); AddedAny = true; } } } } if (hasDeletedOverridenMethods && !MD->isDeleted()) { ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted); } if (hasNonDeletedOverridenMethods && MD->isDeleted()) { ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted); } return AddedAny; } namespace { // Struct for holding all of the extra arguments needed by // DiagnoseInvalidRedeclaration to call Sema::ActOnFunctionDeclarator. struct ActOnFDArgs { Scope *S; Declarator &D; MultiTemplateParamsArg TemplateParamLists; bool AddToScope; }; } // end anonymous namespace namespace { // Callback to only accept typo corrections that have a non-zero edit distance. // Also only accept corrections that have the same parent decl. class DifferentNameValidatorCCC : public CorrectionCandidateCallback { public: DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD, CXXRecordDecl *Parent) : Context(Context), OriginalFD(TypoFD), ExpectedParent(Parent ? Parent->getCanonicalDecl() : nullptr) {} bool ValidateCandidate(const TypoCorrection &candidate) override { if (candidate.getEditDistance() == 0) return false; SmallVector MismatchedParams; for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(), CDeclEnd = candidate.end(); CDecl != CDeclEnd; ++CDecl) { FunctionDecl *FD = dyn_cast(*CDecl); if (FD && !FD->hasBody() && hasSimilarParameters(Context, FD, OriginalFD, MismatchedParams)) { if (CXXMethodDecl *MD = dyn_cast(FD)) { CXXRecordDecl *Parent = MD->getParent(); if (Parent && Parent->getCanonicalDecl() == ExpectedParent) return true; } else if (!ExpectedParent) { return true; } } } return false; } private: ASTContext &Context; FunctionDecl *OriginalFD; CXXRecordDecl *ExpectedParent; }; } // end anonymous namespace void Sema::MarkTypoCorrectedFunctionDefinition(const NamedDecl *F) { TypoCorrectedFunctionDefinitions.insert(F); } /// \brief Generate diagnostics for an invalid function redeclaration. /// /// This routine handles generating the diagnostic messages for an invalid /// function redeclaration, including finding possible similar declarations /// or performing typo correction if there are no previous declarations with /// the same name. /// /// Returns a NamedDecl iff typo correction was performed and substituting in /// the new declaration name does not cause new errors. static NamedDecl *DiagnoseInvalidRedeclaration( Sema &SemaRef, LookupResult &Previous, FunctionDecl *NewFD, ActOnFDArgs &ExtraArgs, bool IsLocalFriend, Scope *S) { DeclarationName Name = NewFD->getDeclName(); DeclContext *NewDC = NewFD->getDeclContext(); SmallVector MismatchedParams; SmallVector, 1> NearMatches; TypoCorrection Correction; bool IsDefinition = ExtraArgs.D.isFunctionDefinition(); unsigned DiagMsg = IsLocalFriend ? diag::err_no_matching_local_friend : diag::err_member_decl_does_not_match; LookupResult Prev(SemaRef, Name, NewFD->getLocation(), IsLocalFriend ? Sema::LookupLocalFriendName : Sema::LookupOrdinaryName, Sema::ForRedeclaration); NewFD->setInvalidDecl(); if (IsLocalFriend) SemaRef.LookupName(Prev, S); else SemaRef.LookupQualifiedName(Prev, NewDC); assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); CXXMethodDecl *MD = dyn_cast(NewFD); if (!Prev.empty()) { for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); Func != FuncEnd; ++Func) { FunctionDecl *FD = dyn_cast(*Func); if (FD && hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) { // Add 1 to the index so that 0 can mean the mismatch didn't // involve a parameter unsigned ParamNum = MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1; NearMatches.push_back(std::make_pair(FD, ParamNum)); } } // If the qualified name lookup yielded nothing, try typo correction } else if ((Correction = SemaRef.CorrectTypo( Prev.getLookupNameInfo(), Prev.getLookupKind(), S, &ExtraArgs.D.getCXXScopeSpec(), llvm::make_unique( SemaRef.Context, NewFD, MD ? MD->getParent() : nullptr), Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) { // Set up everything for the call to ActOnFunctionDeclarator ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(), ExtraArgs.D.getIdentifierLoc()); Previous.clear(); Previous.setLookupName(Correction.getCorrection()); for (TypoCorrection::decl_iterator CDecl = Correction.begin(), CDeclEnd = Correction.end(); CDecl != CDeclEnd; ++CDecl) { FunctionDecl *FD = dyn_cast(*CDecl); if (FD && !FD->hasBody() && hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) { Previous.addDecl(FD); } } bool wasRedeclaration = ExtraArgs.D.isRedeclaration(); NamedDecl *Result; // Retry building the function declaration with the new previous // declarations, and with errors suppressed. { // Trap errors. Sema::SFINAETrap Trap(SemaRef); // TODO: Refactor ActOnFunctionDeclarator so that we can call only the // pieces need to verify the typo-corrected C++ declaration and hopefully // eliminate the need for the parameter pack ExtraArgs. Result = SemaRef.ActOnFunctionDeclarator( ExtraArgs.S, ExtraArgs.D, Correction.getCorrectionDecl()->getDeclContext(), NewFD->getTypeSourceInfo(), Previous, ExtraArgs.TemplateParamLists, ExtraArgs.AddToScope); if (Trap.hasErrorOccurred()) Result = nullptr; } if (Result) { // Determine which correction we picked. Decl *Canonical = Result->getCanonicalDecl(); for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) if ((*I)->getCanonicalDecl() == Canonical) Correction.setCorrectionDecl(*I); // Let Sema know about the correction. SemaRef.MarkTypoCorrectedFunctionDefinition(Result); SemaRef.diagnoseTypo( Correction, SemaRef.PDiag(IsLocalFriend ? diag::err_no_matching_local_friend_suggest : diag::err_member_decl_does_not_match_suggest) << Name << NewDC << IsDefinition); return Result; } // Pretend the typo correction never occurred ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(), ExtraArgs.D.getIdentifierLoc()); ExtraArgs.D.setRedeclaration(wasRedeclaration); Previous.clear(); Previous.setLookupName(Name); } SemaRef.Diag(NewFD->getLocation(), DiagMsg) << Name << NewDC << IsDefinition << NewFD->getLocation(); bool NewFDisConst = false; if (CXXMethodDecl *NewMD = dyn_cast(NewFD)) NewFDisConst = NewMD->isConst(); for (SmallVectorImpl >::iterator NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end(); NearMatch != NearMatchEnd; ++NearMatch) { FunctionDecl *FD = NearMatch->first; CXXMethodDecl *MD = dyn_cast(FD); bool FDisConst = MD && MD->isConst(); bool IsMember = MD || !IsLocalFriend; // FIXME: These notes are poorly worded for the local friend case. if (unsigned Idx = NearMatch->second) { ParmVarDecl *FDParam = FD->getParamDecl(Idx-1); SourceLocation Loc = FDParam->getTypeSpecStartLoc(); if (Loc.isInvalid()) Loc = FD->getLocation(); SemaRef.Diag(Loc, IsMember ? diag::note_member_def_close_param_match : diag::note_local_decl_close_param_match) << Idx << FDParam->getType() << NewFD->getParamDecl(Idx - 1)->getType(); } else if (FDisConst != NewFDisConst) { SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match) << NewFDisConst << FD->getSourceRange().getEnd(); } else SemaRef.Diag(FD->getLocation(), IsMember ? diag::note_member_def_close_match : diag::note_local_decl_close_match); } return nullptr; } static StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) { switch (D.getDeclSpec().getStorageClassSpec()) { default: llvm_unreachable("Unknown storage class!"); case DeclSpec::SCS_auto: case DeclSpec::SCS_register: case DeclSpec::SCS_mutable: SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_typecheck_sclass_func); D.getMutableDeclSpec().ClearStorageClassSpecs(); D.setInvalidType(); break; case DeclSpec::SCS_unspecified: break; case DeclSpec::SCS_extern: if (D.getDeclSpec().isExternInLinkageSpec()) return SC_None; return SC_Extern; case DeclSpec::SCS_static: { if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) { // C99 6.7.1p5: // The declaration of an identifier for a function that has // block scope shall have no explicit storage-class specifier // other than extern // See also (C++ [dcl.stc]p4). SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_block_func); break; } else return SC_Static; } case DeclSpec::SCS_private_extern: return SC_PrivateExtern; } // No explicit storage class has already been returned return SC_None; } static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, DeclContext *DC, QualType &R, TypeSourceInfo *TInfo, StorageClass SC, bool &IsVirtualOkay) { DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); FunctionDecl *NewFD = nullptr; bool isInline = D.getDeclSpec().isInlineSpecified(); if (!SemaRef.getLangOpts().CPlusPlus) { // Determine whether the function was written with a // prototype. This true when: // - there is a prototype in the declarator, or // - the type R of the function is some kind of typedef or other non- // attributed reference to a type name (which eventually refers to a // function type). bool HasPrototype = (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || (!R->getAsAdjusted() && R->isFunctionProtoType()); NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), NameInfo, R, TInfo, SC, isInline, HasPrototype, false); if (D.isInvalidType()) NewFD->setInvalidDecl(); return NewFD; } bool isExplicit = D.getDeclSpec().isExplicitSpecified(); bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); // Check that the return type is not an abstract class type. // For record types, this is done by the AbstractClassUsageDiagnoser once // the class has been completely parsed. if (!DC->isRecord() && SemaRef.RequireNonAbstractType( D.getIdentifierLoc(), R->getAs()->getReturnType(), diag::err_abstract_type_in_decl, SemaRef.AbstractReturnType)) D.setInvalidType(); if (Name.getNameKind() == DeclarationName::CXXConstructorName) { // This is a C++ constructor declaration. assert(DC->isRecord() && "Constructors can only be declared in a member context"); R = SemaRef.CheckConstructorDeclarator(D, R, SC); return CXXConstructorDecl::Create(SemaRef.Context, cast(DC), D.getLocStart(), NameInfo, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false, isConstexpr); } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { R = SemaRef.CheckDestructorDeclarator(D, R, SC); CXXRecordDecl *Record = cast(DC); CXXDestructorDecl *NewDD = CXXDestructorDecl::Create( SemaRef.Context, Record, D.getLocStart(), NameInfo, R, TInfo, isInline, /*isImplicitlyDeclared=*/false); // If the class is complete, then we now create the implicit exception // specification. If the class is incomplete or dependent, we can't do // it yet. if (SemaRef.getLangOpts().CPlusPlus11 && !Record->isDependentType() && Record->getDefinition() && !Record->isBeingDefined() && R->getAs()->getExceptionSpecType() == EST_None) { SemaRef.AdjustDestructorExceptionSpec(Record, NewDD); } IsVirtualOkay = true; return NewDD; } else { SemaRef.Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); D.setInvalidType(); // Create a FunctionDecl to satisfy the function definition parsing // code path. return FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), D.getIdentifierLoc(), Name, R, TInfo, SC, isInline, /*hasPrototype=*/true, isConstexpr); } } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { if (!DC->isRecord()) { SemaRef.Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member); return nullptr; } SemaRef.CheckConversionDeclarator(D, R, SC); IsVirtualOkay = true; return CXXConversionDecl::Create(SemaRef.Context, cast(DC), D.getLocStart(), NameInfo, R, TInfo, isInline, isExplicit, isConstexpr, SourceLocation()); } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) { SemaRef.CheckDeductionGuideDeclarator(D, R, SC); return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getLocStart(), isExplicit, NameInfo, R, TInfo, D.getLocEnd()); } else if (DC->isRecord()) { // If the name of the function is the same as the name of the record, // then this must be an invalid constructor that has a return type. // (The parser checks for a return type and makes the declarator a // constructor if it has no return type). if (Name.getAsIdentifierInfo() && Name.getAsIdentifierInfo() == cast(DC)->getIdentifier()){ SemaRef.Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); return nullptr; } // This is a C++ method declaration. CXXMethodDecl *Ret = CXXMethodDecl::Create(SemaRef.Context, cast(DC), D.getLocStart(), NameInfo, R, TInfo, SC, isInline, isConstexpr, SourceLocation()); IsVirtualOkay = !Ret->isStatic(); return Ret; } else { bool isFriend = SemaRef.getLangOpts().CPlusPlus && D.getDeclSpec().isFriendSpecified(); if (!isFriend && SemaRef.CurContext->isRecord()) return nullptr; // Determine whether the function was written with a // prototype. This true when: // - we're in C++ (where every function has a prototype), return FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), NameInfo, R, TInfo, SC, isInline, true/*HasPrototype*/, isConstexpr); } } enum OpenCLParamType { ValidKernelParam, PtrPtrKernelParam, PtrKernelParam, InvalidAddrSpacePtrKernelParam, InvalidKernelParam, RecordKernelParam }; static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { if (PT->isPointerType()) { QualType PointeeType = PT->getPointeeType(); if (PointeeType->isPointerType()) return PtrPtrKernelParam; if (PointeeType.getAddressSpace() == LangAS::opencl_generic || PointeeType.getAddressSpace() == 0) return InvalidAddrSpacePtrKernelParam; return PtrKernelParam; } // TODO: Forbid the other integer types (size_t, ptrdiff_t...) when they can // be used as builtin types. if (PT->isImageType()) return PtrKernelParam; if (PT->isBooleanType()) return InvalidKernelParam; if (PT->isEventT()) return InvalidKernelParam; // OpenCL extension spec v1.2 s9.5: // This extension adds support for half scalar and vector types as built-in // types that can be used for arithmetic operations, conversions etc. if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16") && PT->isHalfType()) return InvalidKernelParam; if (PT->isRecordType()) return RecordKernelParam; return ValidKernelParam; } static void checkIsValidOpenCLKernelParameter( Sema &S, Declarator &D, ParmVarDecl *Param, llvm::SmallPtrSetImpl &ValidTypes) { QualType PT = Param->getType(); // Cache the valid types we encounter to avoid rechecking structs that are // used again if (ValidTypes.count(PT.getTypePtr())) return; switch (getOpenCLKernelParameterType(S, PT)) { case PtrPtrKernelParam: // OpenCL v1.2 s6.9.a: // A kernel function argument cannot be declared as a // pointer to a pointer type. S.Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_param); D.setInvalidType(); return; case InvalidAddrSpacePtrKernelParam: // OpenCL v1.0 s6.5: // __kernel function arguments declared to be a pointer of a type can point // to one of the following address spaces only : __global, __local or // __constant. S.Diag(Param->getLocation(), diag::err_kernel_arg_address_space); D.setInvalidType(); return; // OpenCL v1.2 s6.9.k: // Arguments to kernel functions in a program cannot be declared with the // built-in scalar types bool, half, size_t, ptrdiff_t, intptr_t, and // uintptr_t or a struct and/or union that contain fields declared to be // one of these built-in scalar types. case InvalidKernelParam: // OpenCL v1.2 s6.8 n: // A kernel function argument cannot be declared // of event_t type. // Do not diagnose half type since it is diagnosed as invalid argument // type for any function elsewhere. if (!PT->isHalfType()) S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT; D.setInvalidType(); return; case PtrKernelParam: case ValidKernelParam: ValidTypes.insert(PT.getTypePtr()); return; case RecordKernelParam: break; } // Track nested structs we will inspect SmallVector VisitStack; // Track where we are in the nested structs. Items will migrate from // VisitStack to HistoryStack as we do the DFS for bad field. SmallVector HistoryStack; HistoryStack.push_back(nullptr); const RecordDecl *PD = PT->castAs()->getDecl(); VisitStack.push_back(PD); assert(VisitStack.back() && "First decl null?"); do { const Decl *Next = VisitStack.pop_back_val(); if (!Next) { assert(!HistoryStack.empty()); // Found a marker, we have gone up a level if (const FieldDecl *Hist = HistoryStack.pop_back_val()) ValidTypes.insert(Hist->getType().getTypePtr()); continue; } // Adds everything except the original parameter declaration (which is not a // field itself) to the history stack. const RecordDecl *RD; if (const FieldDecl *Field = dyn_cast(Next)) { HistoryStack.push_back(Field); RD = Field->getType()->castAs()->getDecl(); } else { RD = cast(Next); } // Add a null marker so we know when we've gone back up a level VisitStack.push_back(nullptr); for (const auto *FD : RD->fields()) { QualType QT = FD->getType(); if (ValidTypes.count(QT.getTypePtr())) continue; OpenCLParamType ParamType = getOpenCLKernelParameterType(S, QT); if (ParamType == ValidKernelParam) continue; if (ParamType == RecordKernelParam) { VisitStack.push_back(FD); continue; } // OpenCL v1.2 s6.9.p: // Arguments to kernel functions that are declared to be a struct or union // do not allow OpenCL objects to be passed as elements of the struct or // union. if (ParamType == PtrKernelParam || ParamType == PtrPtrKernelParam || ParamType == InvalidAddrSpacePtrKernelParam) { S.Diag(Param->getLocation(), diag::err_record_with_pointers_kernel_param) << PT->isUnionType() << PT; } else { S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT; } S.Diag(PD->getLocation(), diag::note_within_field_of_type) << PD->getDeclName(); // We have an error, now let's go back up through history and show where // the offending field came from for (ArrayRef::const_iterator I = HistoryStack.begin() + 1, E = HistoryStack.end(); I != E; ++I) { const FieldDecl *OuterField = *I; S.Diag(OuterField->getLocation(), diag::note_within_field_of_type) << OuterField->getType(); } S.Diag(FD->getLocation(), diag::note_illegal_field_declared_here) << QT->isPointerType() << QT; D.setInvalidType(); return; } } while (!VisitStack.empty()); } /// Find the DeclContext in which a tag is implicitly declared if we see an /// elaborated type specifier in the specified context, and lookup finds /// nothing. static DeclContext *getTagInjectionContext(DeclContext *DC) { while (!DC->isFileContext() && !DC->isFunctionOrMethod()) DC = DC->getParent(); return DC; } /// Find the Scope in which a tag is implicitly declared if we see an /// elaborated type specifier in the specified context, and lookup finds /// nothing. static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) { while (S->isClassScope() || (LangOpts.CPlusPlus && S->isFunctionPrototypeScope()) || ((S->getFlags() & Scope::DeclScope) == 0) || (S->getEntity() && S->getEntity()->isTransparentContext())) S = S->getParent(); return S; } NamedDecl* Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope) { QualType R = TInfo->getType(); assert(R.getTypePtr()->isFunctionType()); // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); StorageClass SC = getFunctionStorageClass(*this, D); if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); if (D.isFirstDeclarationOfMember()) adjustMemberFunctionCC(R, D.isStaticMember(), D.isCtorOrDtor(), D.getIdentifierLoc()); bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = nullptr; bool isMemberSpecialization = false; bool isFunctionTemplateSpecialization = false; bool isDependentClassScopeExplicitSpecialization = false; bool HasExplicitTemplateArgs = false; TemplateArgumentListInfo TemplateArgs; bool isVirtualOkay = false; DeclContext *OriginalDC = DC; bool IsLocalExternDecl = adjustContextForLocalExternDecl(DC); FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC, isVirtualOkay); if (!NewFD) return nullptr; if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer()) NewFD->setTopLevelDeclInObjCContainer(); // Set the lexical context. If this is a function-scope declaration, or has a // C++ scope specifier, or is the object of a friend declaration, the lexical // context will be different from the semantic context. NewFD->setLexicalDeclContext(CurContext); if (IsLocalExternDecl) NewFD->setLocalExternDecl(); if (getLangOpts().CPlusPlus) { bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); bool isConcept = D.getDeclSpec().isConceptSpecified(); isFriend = D.getDeclSpec().isFriendSpecified(); if (isFriend && !isInline && D.isFunctionDefinition()) { // C++ [class.friend]p5 // A function can be defined in a friend declaration of a // class . . . . Such a function is implicitly inline. NewFD->setImplicitlyInline(); } // If this is a method defined in an __interface, and is not a constructor // or an overloaded operator, then set the pure flag (isVirtual will already // return true). if (const CXXRecordDecl *Parent = dyn_cast(NewFD->getDeclContext())) { if (Parent->isInterface() && cast(NewFD)->isUserProvided()) NewFD->setPure(true); // C++ [class.union]p2 // A union can have member functions, but not virtual functions. if (isVirtual && Parent->isUnion()) Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union); } SetNestedNameSpecifier(NewFD, D); isMemberSpecialization = false; isFunctionTemplateSpecialization = false; if (D.isInvalidType()) NewFD->setInvalidDecl(); // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool Invalid = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), D.getName().getKind() == UnqualifiedId::IK_TemplateId ? D.getName().TemplateId : nullptr, TemplateParamLists, isFriend, isMemberSpecialization, Invalid)) { if (TemplateParams->size() > 0) { // This is a function template // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) NewFD->setInvalidDecl(); // A destructor cannot be a template. if (Name.getNameKind() == DeclarationName::CXXDestructorName) { Diag(NewFD->getLocation(), diag::err_destructor_template); NewFD->setInvalidDecl(); } // If we're adding a template to a dependent context, we may need to // rebuilding some of the types used within the template parameter list, // now that we know what the current instantiation is. if (DC->isDependentContext()) { ContextRAII SavedContext(*this, DC); if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) Invalid = true; } FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, NewFD->getLocation(), Name, TemplateParams, NewFD); FunctionTemplate->setLexicalDeclContext(CurContext); NewFD->setDescribedFunctionTemplate(FunctionTemplate); // For source fidelity, store the other template param lists. if (TemplateParamLists.size() > 1) { NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.drop_back(1)); } } else { // This is a function template specialization. isFunctionTemplateSpecialization = true; // For source fidelity, store all the template param lists. if (TemplateParamLists.size() > 0) NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". if (isFriend) { // We want to remove the "template<>", found here. SourceRange RemoveRange = TemplateParams->getSourceRange(); // If we remove the template<> and the name is not a // template-id, we're actually silently creating a problem: // the friend declaration will refer to an untemplated decl, // and clearly the user wants a template specialization. So // we need to insert '<>' after the name. SourceLocation InsertLoc; if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { InsertLoc = D.getName().getSourceRange().getEnd(); InsertLoc = getLocForEndOfToken(InsertLoc); } Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) << Name << RemoveRange << FixItHint::CreateRemoval(RemoveRange) << FixItHint::CreateInsertion(InsertLoc, "<>"); } } } else { // All template param lists were matched against the scope specifier: // this is NOT (an explicit specialization of) a template. if (TemplateParamLists.size() > 0) // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); } if (Invalid) { NewFD->setInvalidDecl(); if (FunctionTemplate) FunctionTemplate->setInvalidDecl(); } // C++ [dcl.fct.spec]p5: // The virtual specifier shall only be used in declarations of // nonstatic class member functions that appear within a // member-specification of a class declaration; see 10.3. // if (isVirtual && !NewFD->isInvalidDecl()) { if (!isVirtualOkay) { Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_non_function); } else if (!CurContext->isRecord()) { // 'virtual' was specified outside of the class. Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); } else if (NewFD->getDescribedFunctionTemplate()) { // C++ [temp.mem]p3: // A member function template shall not be virtual. Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_member_function_template) << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); } else { // Okay: Add virtual to the method. NewFD->setVirtualAsWritten(true); } if (getLangOpts().CPlusPlus14 && NewFD->getReturnType()->isUndeducedType()) Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual); } if (getLangOpts().CPlusPlus14 && (NewFD->isDependentContext() || (isFriend && CurContext->isDependentContext())) && NewFD->getReturnType()->isUndeducedType()) { // If the function template is referenced directly (for instance, as a // member of the current instantiation), pretend it has a dependent type. // This is not really justified by the standard, but is the only sane // thing to do. // FIXME: For a friend function, we have not marked the function as being // a friend yet, so 'isDependentContext' on the FD doesn't work. const FunctionProtoType *FPT = NewFD->getType()->castAs(); QualType Result = SubstAutoType(FPT->getReturnType(), Context.DependentTy); NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo())); } // C++ [dcl.fct.spec]p3: // The inline specifier shall not appear on a block scope function // declaration. if (isInline && !NewFD->isInvalidDecl()) { if (CurContext->isFunctionOrMethod()) { // 'inline' is not allowed on block scope function declaration. Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_declaration_block_scope) << Name << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); } } // C++ [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of a // constructor or conversion function within its class definition; // see 12.3.1 and 12.3.2. if (isExplicit && !NewFD->isInvalidDecl() && !isa(NewFD)) { if (!CurContext->isRecord()) { // 'explicit' was specified outside of the class. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_out_of_class) << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); } else if (!isa(NewFD) && !isa(NewFD)) { // 'explicit' was specified on a function that wasn't a constructor // or conversion function. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_non_ctor_or_conv_function) << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); } } if (isConstexpr) { // C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors // are implicitly inline. NewFD->setImplicitlyInline(); // C++11 [dcl.constexpr]p3: functions declared constexpr are required to // be either constructors or to return a literal type. Therefore, // destructors cannot be declared constexpr. if (isa(NewFD)) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor); } if (isConcept) { // This is a function concept. if (FunctionTemplateDecl *FTD = NewFD->getDescribedFunctionTemplate()) FTD->setConcept(); // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be // applied only to the definition of a function template [...] if (!D.isFunctionDefinition()) { Diag(D.getDeclSpec().getConceptSpecLoc(), diag::err_function_concept_not_defined); NewFD->setInvalidDecl(); } // C++ Concepts TS [dcl.spec.concept]p1: [...] A function concept shall // have no exception-specification and is treated as if it were specified // with noexcept(true) (15.4). [...] if (const FunctionProtoType *FPT = R->getAs()) { if (FPT->hasExceptionSpec()) { SourceRange Range; if (D.isFunctionDeclarator()) Range = D.getFunctionTypeInfo().getExceptionSpecRange(); Diag(NewFD->getLocation(), diag::err_function_concept_exception_spec) << FixItHint::CreateRemoval(Range); NewFD->setInvalidDecl(); } else { Context.adjustExceptionSpec(NewFD, EST_BasicNoexcept); } // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the // following restrictions: // - The declared return type shall have the type bool. if (!Context.hasSameType(FPT->getReturnType(), Context.BoolTy)) { Diag(D.getIdentifierLoc(), diag::err_function_concept_bool_ret); NewFD->setInvalidDecl(); } // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the // following restrictions: // - The declaration's parameter list shall be equivalent to an empty // parameter list. if (FPT->getNumParams() > 0 || FPT->isVariadic()) Diag(NewFD->getLocation(), diag::err_function_concept_with_params); } // C++ Concepts TS [dcl.spec.concept]p2: Every concept definition is // implicity defined to be a constexpr declaration (implicitly inline) NewFD->setImplicitlyInline(); // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not // be declared with the thread_local, inline, friend, or constexpr // specifiers, [...] if (isInline) { Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_concept_decl_invalid_specifiers) << 1 << 1; NewFD->setInvalidDecl(true); } if (isFriend) { Diag(D.getDeclSpec().getFriendSpecLoc(), diag::err_concept_decl_invalid_specifiers) << 1 << 2; NewFD->setInvalidDecl(true); } if (isConstexpr) { Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_concept_decl_invalid_specifiers) << 1 << 3; NewFD->setInvalidDecl(true); } // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be // applied only to the definition of a function template or variable // template, declared in namespace scope. if (isFunctionTemplateSpecialization) { Diag(D.getDeclSpec().getConceptSpecLoc(), diag::err_concept_specified_specialization) << 1; NewFD->setInvalidDecl(true); return NewFD; } } // If __module_private__ was specified, mark the function accordingly. if (D.getDeclSpec().isModulePrivateSpecified()) { if (isFunctionTemplateSpecialization) { SourceLocation ModulePrivateLoc = D.getDeclSpec().getModulePrivateSpecLoc(); Diag(ModulePrivateLoc, diag::err_module_private_specialization) << 0 << FixItHint::CreateRemoval(ModulePrivateLoc); } else { NewFD->setModulePrivate(); if (FunctionTemplate) FunctionTemplate->setModulePrivate(); } } if (isFriend) { if (FunctionTemplate) { FunctionTemplate->setObjectOfFriendDecl(); FunctionTemplate->setAccess(AS_public); } NewFD->setObjectOfFriendDecl(); NewFD->setAccess(AS_public); } // If a function is defined as defaulted or deleted, mark it as such now. // FIXME: Does this ever happen? ActOnStartOfFunctionDef forces the function // definition kind to FDK_Definition. switch (D.getFunctionDefinitionKind()) { case FDK_Declaration: case FDK_Definition: break; case FDK_Defaulted: NewFD->setDefaulted(); break; case FDK_Deleted: NewFD->setDeletedAsWritten(); break; } if (isa(NewFD) && DC == CurContext && D.isFunctionDefinition()) { // C++ [class.mfct]p2: // A member function may be defined (8.4) in its class definition, in // which case it is an inline member function (7.1.2) NewFD->setImplicitlyInline(); } if (SC == SC_Static && isa(NewFD) && !CurContext->isRecord()) { // C++ [class.static]p1: // A data or function member of a class may be declared static // in a class definition, in which case it is a static member of // the class. // Complain about the 'static' specifier if it's on an out-of-line // member function definition. Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } // C++11 [except.spec]p15: // A deallocation function with no exception-specification is treated // as if it were specified with noexcept(true). const FunctionProtoType *FPT = R->getAs(); if ((Name.getCXXOverloadedOperator() == OO_Delete || Name.getCXXOverloadedOperator() == OO_Array_Delete) && getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) NewFD->setType(Context.getFunctionType( FPT->getReturnType(), FPT->getParamTypes(), FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); } // Filter out previous declarations that don't match the scope. FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD), D.getCXXScopeSpec().isNotEmpty() || isMemberSpecialization || isFunctionTemplateSpecialization); // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, SE->getString(), 0)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::iterator I = ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier()); if (I != ExtnameUndeclaredIdentifiers.end()) { if (isDeclExternC(NewFD)) { NewFD->addAttr(I->second); ExtnameUndeclaredIdentifiers.erase(I); } else Diag(NewFD->getLocation(), diag::warn_redefine_extname_not_applied) << /*Variable*/0 << NewFD; } } // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. SmallVector Params; unsigned FTIIdx; if (D.isFunctionDeclarator(FTIIdx)) { DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(FTIIdx).Fun; // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs // function that takes no arguments, not a function that takes a // single void argument. // We let through "const void" here because Sema::GetTypeForDeclarator // already checks for that case. if (FTIHasNonVoidParameters(FTI) && FTI.Params[0].Param) { for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) { ParmVarDecl *Param = cast(FTI.Params[i].Param); assert(Param->getDeclContext() != NewFD && "Was set before ?"); Param->setDeclContext(NewFD); Params.push_back(Param); if (Param->isInvalidDecl()) NewFD->setInvalidDecl(); } } if (!getLangOpts().CPlusPlus) { // In C, find all the tag declarations from the prototype and move them // into the function DeclContext. Remove them from the surrounding tag // injection context of the function, which is typically but not always // the TU. DeclContext *PrototypeTagContext = getTagInjectionContext(NewFD->getLexicalDeclContext()); for (NamedDecl *NonParmDecl : FTI.getDeclsInPrototype()) { auto *TD = dyn_cast(NonParmDecl); // We don't want to reparent enumerators. Look at their parent enum // instead. if (!TD) { if (auto *ECD = dyn_cast(NonParmDecl)) TD = cast(ECD->getDeclContext()); } if (!TD) continue; DeclContext *TagDC = TD->getLexicalDeclContext(); if (!TagDC->containsDecl(TD)) continue; TagDC->removeDecl(TD); TD->setDeclContext(NewFD); NewFD->addDecl(TD); // Preserve the lexical DeclContext if it is not the surrounding tag // injection context of the FD. In this example, the semantic context of // E will be f and the lexical context will be S, while both the // semantic and lexical contexts of S will be f: // void f(struct S { enum E { a } f; } s); if (TagDC != PrototypeTagContext) TD->setLexicalDeclContext(TagDC); } } } else if (const FunctionProtoType *FT = R->getAs()) { // When we're declaring a function with a typedef, typeof, etc as in the // following example, we'll need to synthesize (unnamed) // parameters for use in the declaration. // // @code // typedef void fn(int); // fn f; // @endcode // Synthesize a parameter for each argument type. for (const auto &AI : FT->param_types()) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), AI); Param->setScopeInfo(0, Params.size()); Params.push_back(Param); } } else { assert(R->isFunctionNoProtoType() && NewFD->getNumParams() == 0 && "Should not need args for typedef of non-prototype fn"); } // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Params); if (D.getDeclSpec().isNoreturnSpecified()) NewFD->addAttr( ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(), Context, 0)); // Functions returning a variably modified type violate C99 6.7.5.2p2 // because all functions have linkage. if (!NewFD->isInvalidDecl() && NewFD->getReturnType()->isVariablyModifiedType()) { Diag(NewFD->getLocation(), diag::err_vm_func_decl); NewFD->setInvalidDecl(); } // Apply an implicit SectionAttr if #pragma code_seg is active. if (CodeSegStack.CurrentValue && D.isFunctionDefinition() && !NewFD->hasAttr()) { NewFD->addAttr( SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate, CodeSegStack.CurrentValue->getString(), CodeSegStack.CurrentPragmaLocation)); if (UnifySection(CodeSegStack.CurrentValue->getString(), ASTContext::PSF_Implicit | ASTContext::PSF_Execute | ASTContext::PSF_Read, NewFD)) NewFD->dropAttr(); } // Handle attributes. ProcessDeclAttributes(S, NewFD, D); if (getLangOpts().OpenCL) { // OpenCL v1.1 s6.5: Using an address space qualifier in a function return // type declaration will generate a compilation error. unsigned AddressSpace = NewFD->getReturnType().getAddressSpace(); if (AddressSpace == LangAS::opencl_local || AddressSpace == LangAS::opencl_global || AddressSpace == LangAS::opencl_constant) { Diag(NewFD->getLocation(), diag::err_opencl_return_value_with_address_space); NewFD->setInvalidDecl(); } } if (!getLangOpts().CPlusPlus) { // Perform semantic checking on the function declaration. if (!NewFD->isInvalidDecl() && NewFD->isMain()) CheckMain(NewFD, D.getDeclSpec()); if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) CheckMSVCRTEntryPoint(NewFD); if (!NewFD->isInvalidDecl()) D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isMemberSpecialization)); else if (!Previous.empty()) // Recover gracefully from an invalid redeclaration. D.setRedeclaration(true); assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); // Diagnose no-prototype function declarations with calling conventions that // don't support variadic calls. Only do this in C and do it after merging // possibly prototyped redeclarations. const FunctionType *FT = NewFD->getType()->castAs(); if (isa(FT) && !D.isFunctionDefinition()) { CallingConv CC = FT->getExtInfo().getCC(); if (!supportsVariadicCall(CC)) { // Windows system headers sometimes accidentally use stdcall without // (void) parameters, so we relax this to a warning. int DiagID = CC == CC_X86StdCall ? diag::warn_cconv_knr : diag::err_cconv_knr; Diag(NewFD->getLocation(), DiagID) << FunctionType::getNameForCallConv(CC); } } } else { // C++11 [replacement.functions]p3: // The program's definitions shall not be specified as inline. // // N.B. We diagnose declarations instead of definitions per LWG issue 2340. // // Suppress the diagnostic if the function is __attribute__((used)), since // that forces an external definition to be emitted. if (D.getDeclSpec().isInlineSpecified() && NewFD->isReplaceableGlobalAllocationFunction() && !NewFD->hasAttr()) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::ext_operator_new_delete_declared_inline) << NewFD->getDeclName(); // If the declarator is a template-id, translate the parser's template // argument list into our AST format. if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { TemplateIdAnnotation *TemplateId = D.getName().TemplateId; TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); HasExplicitTemplateArgs = true; if (NewFD->isInvalidDecl()) { HasExplicitTemplateArgs = false; } else if (FunctionTemplate) { // Function template with explicit template arguments. Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); HasExplicitTemplateArgs = false; } else { assert((isFunctionTemplateSpecialization || D.getDeclSpec().isFriendSpecified()) && "should have a 'template<>' for this decl"); // "friend void foo<>(int);" is an implicit specialization decl. isFunctionTemplateSpecialization = true; } } else if (isFriend && isFunctionTemplateSpecialization) { // This combination is only possible in a recovery case; the user // wrote something like: // template <> friend void foo(int); // which we're recovering from as if the user had written: // friend void foo<>(int); // Go ahead and fake up a template id. HasExplicitTemplateArgs = true; TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); } // We do not add HD attributes to specializations here because // they may have different constexpr-ness compared to their // templates and, after maybeAddCUDAHostDeviceAttrs() is applied, // may end up with different effective targets. Instead, a // specialization inherits its target attributes from its template // in the CheckFunctionTemplateSpecialization() call below. if (getLangOpts().CUDA & !isFunctionTemplateSpecialization) maybeAddCUDAHostDeviceAttrs(NewFD, Previous); // If it's a friend (and only if it's a friend), it's possible // that either the specialized function type or the specialized // template is dependent, and therefore matching will fail. In // this case, don't check the specialization yet. bool InstantiationDependent = false; if (isFunctionTemplateSpecialization && isFriend && (NewFD->getType()->isDependentType() || DC->isDependentContext() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, InstantiationDependent))) { assert(HasExplicitTemplateArgs && "friend function specialization without template args"); if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, Previous)) NewFD->setInvalidDecl(); } else if (isFunctionTemplateSpecialization) { if (CurContext->isDependentContext() && CurContext->isRecord() && !isFriend) { isDependentClassScopeExplicitSpecialization = true; Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? diag::ext_function_specialization_in_class : diag::err_function_specialization_in_class) << NewFD->getDeclName(); } else if (CheckFunctionTemplateSpecialization(NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), Previous)) NewFD->setInvalidDecl(); // C++ [dcl.stc]p1: // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) FunctionTemplateSpecializationInfo *Info = NewFD->getTemplateSpecializationInfo(); if (Info && SC != SC_None) { if (SC != Info->getTemplate()->getTemplatedDecl()->getStorageClass()) Diag(NewFD->getLocation(), diag::err_explicit_specialization_inconsistent_storage_class) << SC << FixItHint::CreateRemoval( D.getDeclSpec().getStorageClassSpecLoc()); else Diag(NewFD->getLocation(), diag::ext_explicit_specialization_storage_class) << FixItHint::CreateRemoval( D.getDeclSpec().getStorageClassSpecLoc()); } } else if (isMemberSpecialization && isa(NewFD)) { if (CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); } // Perform semantic checking on the function declaration. if (!isDependentClassScopeExplicitSpecialization) { if (!NewFD->isInvalidDecl() && NewFD->isMain()) CheckMain(NewFD, D.getDeclSpec()); if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) CheckMSVCRTEntryPoint(NewFD); if (!NewFD->isInvalidDecl()) D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isMemberSpecialization)); else if (!Previous.empty()) // Recover gracefully from an invalid redeclaration. D.setRedeclaration(true); } assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); NamedDecl *PrincipalDecl = (FunctionTemplate ? cast(FunctionTemplate) : NewFD); if (isFriend && NewFD->getPreviousDecl()) { AccessSpecifier Access = AS_public; if (!NewFD->isInvalidDecl()) Access = NewFD->getPreviousDecl()->getAccess(); NewFD->setAccess(Access); if (FunctionTemplate) FunctionTemplate->setAccess(Access); } if (NewFD->isOverloadedOperator() && !DC->isRecord() && PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDecl(); CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), PrevTemplate ? PrevTemplate->getTemplateParameters() : nullptr, D.getDeclSpec().isFriendSpecified() ? (D.isFunctionDefinition() ? TPC_FriendFunctionTemplateDefinition : TPC_FriendFunctionTemplate) : (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && DC->isDependentContext()) ? TPC_ClassTemplateMember : TPC_FunctionTemplate); } if (NewFD->isInvalidDecl()) { // Ignore all the rest of this. } else if (!D.isRedeclaration()) { struct ActOnFDArgs ExtraArgs = { S, D, TemplateParamLists, AddToScope }; // Fake up an access specifier if it's supposed to be a class member. if (isa(NewFD->getDeclContext())) NewFD->setAccess(AS_public); // Qualified decls generally require a previous declaration. if (D.getCXXScopeSpec().isSet()) { // ...with the major exception of templated-scope or // dependent-scope friend declarations. // TODO: we currently also suppress this check in dependent // contexts because (1) the parameter depth will be off when // matching friend templates and (2) we might actually be // selecting a friend based on a dependent factor. But there // are situations where these conditions don't apply and we // can actually do this check immediately. if (isFriend && (TemplateParamLists.size() || D.getCXXScopeSpec().getScopeRep()->isDependent() || CurContext->isDependentContext())) { // ignore these } else { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there // was no such member function declared (C++ [class.mfct]p2, // C++ [namespace.memdef]p2). For example: // // class X { // void f() const; // }; // // void X::f() { } // ill-formed // // Complain about this problem, and attempt to suggest close // matches (e.g., those that differ only in cv-qualifiers and // whether the parameter types are references). if (NamedDecl *Result = DiagnoseInvalidRedeclaration( *this, Previous, NewFD, ExtraArgs, false, nullptr)) { AddToScope = ExtraArgs.AddToScope; return Result; } } // Unqualified local friend declarations are required to resolve // to something. } else if (isFriend && cast(CurContext)->isLocalClass()) { if (NamedDecl *Result = DiagnoseInvalidRedeclaration( *this, Previous, NewFD, ExtraArgs, true, S)) { AddToScope = ExtraArgs.AddToScope; return Result; } } } else if (!D.isFunctionDefinition() && isa(NewFD) && NewFD->isOutOfLine() && !isFriend && !isFunctionTemplateSpecialization && !isMemberSpecialization) { // An out-of-line member function declaration must also be a // definition (C++ [class.mfct]p2). // Note that this is not the case for explicit specializations of // function templates or member functions of class templates, per // C++ [temp.expl.spec]p2. We also allow these declarations as an // extension for compatibility with old SWIG code which likes to // generate them. Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); } } ProcessPragmaWeak(S, NewFD); checkAttributesAfterMerging(*this, *NewFD); AddKnownFunctionAttributes(NewFD); if (NewFD->hasAttr() && !NewFD->getType()->getAs()) { Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) << NewFD; // Turn this into a variadic function with no parameters. const FunctionType *FT = NewFD->getType()->getAs(); FunctionProtoType::ExtProtoInfo EPI( Context.getDefaultCallingConvention(true, false)); EPI.Variadic = true; EPI.ExtInfo = FT->getExtInfo(); QualType R = Context.getFunctionType(FT->getReturnType(), None, EPI); NewFD->setType(R); } // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this function. if (!DC->isRecord() && NewFD->isExternallyVisible()) AddPushedVisibilityAttribute(NewFD); // If there's a #pragma clang arc_cf_code_audited in scope, consider // marking the function. AddCFAuditedAttribute(NewFD); // If this is a function definition, check if we have to apply optnone due to // a pragma. if(D.isFunctionDefinition()) AddRangeBasedOptnone(NewFD); // If this is the first declaration of an extern C variable, update // the map of such variables. if (NewFD->isFirstDecl() && !NewFD->isInvalidDecl() && isIncompleteDeclExternC(*this, NewFD)) RegisterLocallyScopedExternCDecl(NewFD, S); // Set this FunctionDecl's range up to the right paren. NewFD->setRangeEnd(D.getSourceRange().getEnd()); if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast(Previous.getRepresentativeDecl()), NewFD, isMemberSpecialization || isFunctionTemplateSpecialization, D.isFunctionDefinition()); } if (getLangOpts().CUDA) { IdentifierInfo *II = NewFD->getIdentifier(); if (II && II->isStr("cudaConfigureCall") && !NewFD->isInvalidDecl() && NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (!R->getAs()->getReturnType()->isScalarType()) Diag(NewFD->getLocation(), diag::err_config_scalar_return); Context.setcudaConfigureCallDecl(NewFD); } // Variadic functions, other than a *declaration* of printf, are not allowed // in device-side CUDA code, unless someone passed // -fcuda-allow-variadic-functions. if (!getLangOpts().CUDAAllowVariadicFunctions && NewFD->isVariadic() && (NewFD->hasAttr() || NewFD->hasAttr()) && !(II && II->isStr("printf") && NewFD->isExternC() && !D.isFunctionDefinition())) { Diag(NewFD->getLocation(), diag::err_variadic_device_fn); } } MarkUnusedFileScopedDecl(NewFD); if (getLangOpts().CPlusPlus) { if (FunctionTemplate) { if (NewFD->isInvalidDecl()) FunctionTemplate->setInvalidDecl(); return FunctionTemplate; } if (isMemberSpecialization && !NewFD->isInvalidDecl()) CompleteMemberSpecialization(NewFD, Previous); } if (NewFD->hasAttr()) { // OpenCL v1.2 s6.8 static is invalid for kernel functions. if ((getLangOpts().OpenCLVersion >= 120) && (SC == SC_Static)) { Diag(D.getIdentifierLoc(), diag::err_static_kernel); D.setInvalidType(); } // OpenCL v1.2, s6.9 -- Kernels can only have return type void. if (!NewFD->getReturnType()->isVoidType()) { SourceRange RTRange = NewFD->getReturnTypeSourceRange(); Diag(D.getIdentifierLoc(), diag::err_expected_kernel_void_return_type) << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void") : FixItHint()); D.setInvalidType(); } llvm::SmallPtrSet ValidTypes; for (auto Param : NewFD->parameters()) checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes); } for (const ParmVarDecl *Param : NewFD->parameters()) { QualType PT = Param->getType(); // OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value // types. if (getLangOpts().OpenCLVersion >= 200) { if(const PipeType *PipeTy = PT->getAs()) { QualType ElemTy = PipeTy->getElementType(); if (ElemTy->isReferenceType() || ElemTy->isPointerType()) { Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type ); D.setInvalidType(); } } } } // Here we have an function template explicit specialization at class scope. // The actually specialization will be postponed to template instatiation // time via the ClassScopeFunctionSpecializationDecl node. if (isDependentClassScopeExplicitSpecialization) { ClassScopeFunctionSpecializationDecl *NewSpec = ClassScopeFunctionSpecializationDecl::Create( Context, CurContext, SourceLocation(), cast(NewFD), HasExplicitTemplateArgs, TemplateArgs); CurContext->addDecl(NewSpec); AddToScope = false; } return NewFD; } /// \brief Checks if the new declaration declared in dependent context must be /// put in the same redeclaration chain as the specified declaration. /// /// \param D Declaration that is checked. /// \param PrevDecl Previous declaration found with proper lookup method for the /// same declaration name. /// \returns True if D must be added to the redeclaration chain which PrevDecl /// belongs to. /// bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) { // Any declarations should be put into redeclaration chains except for // friend declaration in a dependent context that names a function in // namespace scope. // // This allows to compile code like: // // void func(); // template class C1 { friend void func() { } }; // template class C2 { friend void func() { } }; // // This code snippet is a valid code unless both templates are instantiated. return !(D->getLexicalDeclContext()->isDependentContext() && D->getDeclContext()->isFileContext() && D->getFriendObjectKind() != Decl::FOK_None); } /// \brief Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration /// NewFD. This routine performs all semantic checking that does not /// require the actual declarator involved in the declaration, and is /// used both for the declaration of functions as they are parsed /// (called via ActOnDeclarator) and for the declaration of functions /// that have been instantiated via C++ template instantiation (called /// via InstantiateDecl). /// /// \param IsMemberSpecialization whether this new function declaration is /// a member specialization (that replaces any definition provided by the /// previous declaration). /// /// This sets NewFD->isInvalidDecl() to true if there was an error. /// /// \returns true if the function declaration is a redeclaration. bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsMemberSpecialization) { assert(!NewFD->getReturnType()->isVariablyModifiedType() && "Variably modified return types are not handled here"); // Determine whether the type of this function should be merged with // a previous visible declaration. This never happens for functions in C++, // and always happens in C if the previous declaration was visible. bool MergeTypeWithPrevious = !getLangOpts().CPlusPlus && !Previous.isShadowed(); bool Redeclaration = false; NamedDecl *OldDecl = nullptr; // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. if (!Previous.empty()) { // Determine whether NewFD is an overload of PrevDecl or // a declaration that requires merging. If it's an overload, // there's no more work to do here; we'll just add the new // function to the scope. if (!AllowOverloadingOfFunction(Previous, Context)) { NamedDecl *Candidate = Previous.getRepresentativeDecl(); if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) { Redeclaration = true; OldDecl = Candidate; } } else { switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { case Ovl_Match: Redeclaration = true; break; case Ovl_NonFunction: Redeclaration = true; break; case Ovl_Overload: Redeclaration = false; break; } if (!getLangOpts().CPlusPlus && !NewFD->hasAttr()) { // If a function name is overloadable in C, then every function // with that name must be marked "overloadable". Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) << Redeclaration << NewFD; NamedDecl *OverloadedDecl = Redeclaration ? OldDecl : Previous.getRepresentativeDecl(); Diag(OverloadedDecl->getLocation(), diag::note_attribute_overloadable_prev_overload); NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); } } } // Check for a previous extern "C" declaration with this name. if (!Redeclaration && checkForConflictWithNonVisibleExternC(*this, NewFD, Previous)) { if (!Previous.empty()) { // This is an extern "C" declaration with the same name as a previous // declaration, and thus redeclares that entity... Redeclaration = true; OldDecl = Previous.getFoundDecl(); MergeTypeWithPrevious = false; // ... except in the presence of __attribute__((overloadable)). if (OldDecl->hasAttr()) { if (!getLangOpts().CPlusPlus && !NewFD->hasAttr()) { Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) << Redeclaration << NewFD; Diag(Previous.getFoundDecl()->getLocation(), diag::note_attribute_overloadable_prev_overload); NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); } if (IsOverload(NewFD, cast(OldDecl), false)) { Redeclaration = false; OldDecl = nullptr; } } } } // C++11 [dcl.constexpr]p8: // A constexpr specifier for a non-static member function that is not // a constructor declares that member function to be const. // // This needs to be delayed until we know whether this is an out-of-line // definition of a static member function. // // This rule is not present in C++1y, so we produce a backwards // compatibility warning whenever it happens in C++11. CXXMethodDecl *MD = dyn_cast(NewFD); if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() && !MD->isStatic() && !isa(MD) && (MD->getTypeQualifiers() & Qualifiers::Const) == 0) { CXXMethodDecl *OldMD = nullptr; if (OldDecl) OldMD = dyn_cast_or_null(OldDecl->getAsFunction()); if (!OldMD || !OldMD->isStatic()) { const FunctionProtoType *FPT = MD->getType()->castAs(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.TypeQuals |= Qualifiers::Const; MD->setType(Context.getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI)); // Warn that we did this, if we're not performing template instantiation. // In that case, we'll have warned already when the template was defined. if (!inTemplateInstantiation()) { SourceLocation AddConstLoc; if (FunctionTypeLoc FTL = MD->getTypeSourceInfo()->getTypeLoc() .IgnoreParens().getAs()) AddConstLoc = getLocForEndOfToken(FTL.getRParenLoc()); Diag(MD->getLocation(), diag::warn_cxx14_compat_constexpr_not_const) << FixItHint::CreateInsertion(AddConstLoc, " const"); } } } if (Redeclaration) { // NewFD and OldDecl represent declarations that need to be // merged. if (MergeFunctionDecl(NewFD, OldDecl, S, MergeTypeWithPrevious)) { NewFD->setInvalidDecl(); return Redeclaration; } Previous.clear(); Previous.addDecl(OldDecl); if (FunctionTemplateDecl *OldTemplateDecl = dyn_cast(OldDecl)) { NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); if (CXXMethodDecl *Method = dyn_cast(NewTemplateDecl->getTemplatedDecl())) { Method->setAccess(OldTemplateDecl->getAccess()); NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); } // If this is an explicit specialization of a member that is a function // template, mark it as a member specialization. if (IsMemberSpecialization && NewTemplateDecl->getInstantiatedFromMemberTemplate()) { NewTemplateDecl->setMemberSpecialization(); assert(OldTemplateDecl->isMemberSpecialization()); // Explicit specializations of a member template do not inherit deleted // status from the parent member template that they are specializing. if (OldTemplateDecl->getTemplatedDecl()->isDeleted()) { FunctionDecl *const OldTemplatedDecl = OldTemplateDecl->getTemplatedDecl(); // FIXME: This assert will not hold in the presence of modules. assert(OldTemplatedDecl->getCanonicalDecl() == OldTemplatedDecl); // FIXME: We need an update record for this AST mutation. OldTemplatedDecl->setDeletedAsWritten(false); } } } else { if (shouldLinkDependentDeclWithPrevious(NewFD, OldDecl)) { // This needs to happen first so that 'inline' propagates. NewFD->setPreviousDeclaration(cast(OldDecl)); if (isa(NewFD)) NewFD->setAccess(OldDecl->getAccess()); } } } // Semantic checking for this function declaration (in isolation). if (getLangOpts().CPlusPlus) { // C++-specific checks. if (CXXConstructorDecl *Constructor = dyn_cast(NewFD)) { CheckConstructor(Constructor); } else if (CXXDestructorDecl *Destructor = dyn_cast(NewFD)) { CXXRecordDecl *Record = Destructor->getParent(); QualType ClassType = Context.getTypeDeclType(Record); // FIXME: Shouldn't we be able to perform this check even when the class // type is dependent? Both gcc and edg can handle that. if (!ClassType->isDependentType()) { DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); if (NewFD->getDeclName() != Name) { Diag(NewFD->getLocation(), diag::err_destructor_name); NewFD->setInvalidDecl(); return Redeclaration; } } } else if (CXXConversionDecl *Conversion = dyn_cast(NewFD)) { ActOnConversionDeclarator(Conversion); } else if (auto *Guide = dyn_cast(NewFD)) { if (auto *TD = Guide->getDescribedFunctionTemplate()) CheckDeductionGuideTemplate(TD); // A deduction guide is not on the list of entities that can be // explicitly specialized. if (Guide->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) Diag(Guide->getLocStart(), diag::err_deduction_guide_specialized) << /*explicit specialization*/ 1; } // Find any virtual functions that this function overrides. if (CXXMethodDecl *Method = dyn_cast(NewFD)) { if (!Method->isFunctionTemplateSpecialization() && !Method->getDescribedFunctionTemplate() && Method->isCanonicalDecl()) { if (AddOverriddenMethods(Method->getParent(), Method)) { // If the function was marked as "static", we have a problem. if (NewFD->getStorageClass() == SC_Static) { ReportOverrides(*this, diag::err_static_overrides_virtual, Method); } } } if (Method->isStatic()) checkThisInStaticMemberFunctionType(Method); } // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && CheckOverloadedOperatorDeclaration(NewFD)) { NewFD->setInvalidDecl(); return Redeclaration; } // Extra checking for C++0x literal operators (C++0x [over.literal]). if (NewFD->getLiteralIdentifier() && CheckLiteralOperatorDeclaration(NewFD)) { NewFD->setInvalidDecl(); return Redeclaration; } // In C++, check default arguments now that we have merged decls. Unless // the lexical context is the class, because in this case this is done // during delayed parsing anyway. if (!CurContext->isRecord()) CheckCXXDefaultArguments(NewFD); // If this function declares a builtin function, check the type of this // declaration against the expected type for the builtin. if (unsigned BuiltinID = NewFD->getBuiltinID()) { ASTContext::GetBuiltinTypeError Error; LookupPredefedObjCSuperType(*this, S, NewFD->getIdentifier()); QualType T = Context.GetBuiltinType(BuiltinID, Error); // If the type of the builtin differs only in its exception // specification, that's OK. // FIXME: If the types do differ in this way, it would be better to // retain the 'noexcept' form of the type. if (!T.isNull() && !Context.hasSameFunctionTypeIgnoringExceptionSpec(T, NewFD->getType())) // The type of this function differs from the type of the builtin, // so forget about the builtin entirely. Context.BuiltinInfo.forgetBuiltin(BuiltinID, Context.Idents); } // If this function is declared as being extern "C", then check to see if // the function returns a UDT (class, struct, or union type) that is not C // compatible, and if it does, warn the user. // But, issue any diagnostic on the first declaration only. if (Previous.empty() && NewFD->isExternC()) { QualType R = NewFD->getReturnType(); if (R->isIncompleteType() && !R->isVoidType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete) << NewFD << R; else if (!R.isPODType(Context) && !R->isVoidType() && !R->isObjCObjectPointerType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R; } // C++1z [dcl.fct]p6: // [...] whether the function has a non-throwing exception-specification // [is] part of the function type // // This results in an ABI break between C++14 and C++17 for functions whose // declared type includes an exception-specification in a parameter or // return type. (Exception specifications on the function itself are OK in // most cases, and exception specifications are not permitted in most other // contexts where they could make it into a mangling.) if (!getLangOpts().CPlusPlus1z && !NewFD->getPrimaryTemplate()) { auto HasNoexcept = [&](QualType T) -> bool { // Strip off declarator chunks that could be between us and a function // type. We don't need to look far, exception specifications are very // restricted prior to C++17. if (auto *RT = T->getAs()) T = RT->getPointeeType(); else if (T->isAnyPointerType()) T = T->getPointeeType(); else if (auto *MPT = T->getAs()) T = MPT->getPointeeType(); if (auto *FPT = T->getAs()) if (FPT->isNothrow(Context)) return true; return false; }; auto *FPT = NewFD->getType()->castAs(); bool AnyNoexcept = HasNoexcept(FPT->getReturnType()); for (QualType T : FPT->param_types()) AnyNoexcept |= HasNoexcept(T); if (AnyNoexcept) Diag(NewFD->getLocation(), diag::warn_cxx1z_compat_exception_spec_in_signature) << NewFD; } if (!Redeclaration && LangOpts.CUDA) checkCUDATargetOverload(NewFD, Previous); } return Redeclaration; } void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { // C++11 [basic.start.main]p3: // A program that [...] declares main to be inline, static or // constexpr is ill-formed. // C11 6.7.4p4: In a hosted environment, no function specifier(s) shall // appear in a declaration of main. // static main is not an error under C99, but we should warn about it. // We accept _Noreturn main as an extension. if (FD->getStorageClass() == SC_Static) Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus ? diag::err_static_main : diag::warn_static_main) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); if (FD->isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_main) << FixItHint::CreateRemoval(DS.getInlineSpecLoc()); if (DS.isNoreturnSpecified()) { SourceLocation NoreturnLoc = DS.getNoreturnSpecLoc(); SourceRange NoreturnRange(NoreturnLoc, getLocForEndOfToken(NoreturnLoc)); Diag(NoreturnLoc, diag::ext_noreturn_main); Diag(NoreturnLoc, diag::note_main_remove_noreturn) << FixItHint::CreateRemoval(NoreturnRange); } if (FD->isConstexpr()) { Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main) << FixItHint::CreateRemoval(DS.getConstexprSpecLoc()); FD->setConstexpr(false); } if (getLangOpts().OpenCL) { Diag(FD->getLocation(), diag::err_opencl_no_main) << FD->hasAttr(); FD->setInvalidDecl(); return; } QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); const FunctionType* FT = T->castAs(); if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) { // In C with GNU extensions we allow main() to have non-integer return // type, but we should warn about the extension, and we disable the // implicit-return-zero rule. // GCC in C mode accepts qualified 'int'. if (Context.hasSameUnqualifiedType(FT->getReturnType(), Context.IntTy)) FD->setHasImplicitReturnZero(true); else { Diag(FD->getTypeSpecStartLoc(), diag::ext_main_returns_nonint); SourceRange RTRange = FD->getReturnTypeSourceRange(); if (RTRange.isValid()) Diag(RTRange.getBegin(), diag::note_main_change_return_type) << FixItHint::CreateReplacement(RTRange, "int"); } } else { // In C and C++, main magically returns 0 if you fall off the end; // set the flag which tells us that. // This is C++ [basic.start.main]p5 and C99 5.1.2.2.3. // All the standards say that main() should return 'int'. if (Context.hasSameType(FT->getReturnType(), Context.IntTy)) FD->setHasImplicitReturnZero(true); else { // Otherwise, this is just a flat-out error. SourceRange RTRange = FD->getReturnTypeSourceRange(); Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint) << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "int") : FixItHint()); FD->setInvalidDecl(true); } } // Treat protoless main() as nullary. if (isa(FT)) return; const FunctionProtoType* FTP = cast(FT); unsigned nparams = FTP->getNumParams(); assert(FD->getNumParams() == nparams); bool HasExtraParameters = (nparams > 3); if (FTP->isVariadic()) { Diag(FD->getLocation(), diag::ext_variadic_main); // FIXME: if we had information about the location of the ellipsis, we // could add a FixIt hint to remove it as a parameter. } // Darwin passes an undocumented fourth argument of type char**. If // other platforms start sprouting these, the logic below will start // getting shifty. if (nparams == 4 && Context.getTargetInfo().getTriple().isOSDarwin()) HasExtraParameters = false; if (HasExtraParameters) { Diag(FD->getLocation(), diag::err_main_surplus_args) << nparams; FD->setInvalidDecl(true); nparams = 3; } // FIXME: a lot of the following diagnostics would be improved // if we had some location information about types. QualType CharPP = Context.getPointerType(Context.getPointerType(Context.CharTy)); QualType Expected[] = { Context.IntTy, CharPP, CharPP, CharPP }; for (unsigned i = 0; i < nparams; ++i) { QualType AT = FTP->getParamType(i); bool mismatch = true; if (Context.hasSameUnqualifiedType(AT, Expected[i])) mismatch = false; else if (Expected[i] == CharPP) { // As an extension, the following forms are okay: // char const ** // char const * const * // char * const * QualifierCollector qs; const PointerType* PT; if ((PT = qs.strip(AT)->getAs()) && (PT = qs.strip(PT->getPointeeType())->getAs()) && Context.hasSameType(QualType(qs.strip(PT->getPointeeType()), 0), Context.CharTy)) { qs.removeConst(); mismatch = !qs.empty(); } } if (mismatch) { Diag(FD->getLocation(), diag::err_main_arg_wrong) << i << Expected[i]; // TODO: suggest replacing given type with expected type FD->setInvalidDecl(true); } } if (nparams == 1 && !FD->isInvalidDecl()) { Diag(FD->getLocation(), diag::warn_main_one_arg); } if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD; FD->setInvalidDecl(); } } void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) { QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); const FunctionType *FT = T->castAs(); // Set an implicit return of 'zero' if the function can return some integral, // enumeration, pointer or nullptr type. if (FT->getReturnType()->isIntegralOrEnumerationType() || FT->getReturnType()->isAnyPointerType() || FT->getReturnType()->isNullPtrType()) // DllMain is exempt because a return value of zero means it failed. if (FD->getName() != "DllMain") FD->setHasImplicitReturnZero(true); if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD; FD->setInvalidDecl(); } } bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { // FIXME: Need strict checking. In C89, we need to check for // any assignment, increment, decrement, function-calls, or // commas outside of a sizeof. In C99, it's the same list, // except that the aforementioned are allowed in unevaluated // expressions. Everything else falls under the // "may accept other forms of constant expressions" exception. // (We never end up here for C++, so the constant expression // rules there don't matter.) const Expr *Culprit; if (Init->isConstantInitializer(Context, false, &Culprit)) return false; Diag(Culprit->getExprLoc(), diag::err_init_element_not_constant) << Culprit->getSourceRange(); return true; } namespace { // Visits an initialization expression to see if OrigDecl is evaluated in // its own initialization and throws a warning if it does. class SelfReferenceChecker : public EvaluatedExprVisitor { Sema &S; Decl *OrigDecl; bool isRecordType; bool isPODType; bool isReferenceType; bool isInitList; llvm::SmallVector InitFieldIndex; public: typedef EvaluatedExprVisitor Inherited; SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context), S(S), OrigDecl(OrigDecl) { isPODType = false; isRecordType = false; isReferenceType = false; isInitList = false; if (ValueDecl *VD = dyn_cast(OrigDecl)) { isPODType = VD->getType().isPODType(S.Context); isRecordType = VD->getType()->isRecordType(); isReferenceType = VD->getType()->isReferenceType(); } } // For most expressions, just call the visitor. For initializer lists, // track the index of the field being initialized since fields are // initialized in order allowing use of previously initialized fields. void CheckExpr(Expr *E) { InitListExpr *InitList = dyn_cast(E); if (!InitList) { Visit(E); return; } // Track and increment the index here. isInitList = true; InitFieldIndex.push_back(0); for (auto Child : InitList->children()) { CheckExpr(cast(Child)); ++InitFieldIndex.back(); } InitFieldIndex.pop_back(); } // Returns true if MemberExpr is checked and no further checking is needed. // Returns false if additional checking is required. bool CheckInitListMemberExpr(MemberExpr *E, bool CheckReference) { llvm::SmallVector Fields; Expr *Base = E; bool ReferenceField = false; // Get the field memebers used. while (MemberExpr *ME = dyn_cast(Base)) { FieldDecl *FD = dyn_cast(ME->getMemberDecl()); if (!FD) return false; Fields.push_back(FD); if (FD->getType()->isReferenceType()) ReferenceField = true; Base = ME->getBase()->IgnoreParenImpCasts(); } // Keep checking only if the base Decl is the same. DeclRefExpr *DRE = dyn_cast(Base); if (!DRE || DRE->getDecl() != OrigDecl) return false; // A reference field can be bound to an unininitialized field. if (CheckReference && !ReferenceField) return true; // Convert FieldDecls to their index number. llvm::SmallVector UsedFieldIndex; for (const FieldDecl *I : llvm::reverse(Fields)) UsedFieldIndex.push_back(I->getFieldIndex()); // See if a warning is needed by checking the first difference in index // numbers. If field being used has index less than the field being // initialized, then the use is safe. for (auto UsedIter = UsedFieldIndex.begin(), UsedEnd = UsedFieldIndex.end(), OrigIter = InitFieldIndex.begin(), OrigEnd = InitFieldIndex.end(); UsedIter != UsedEnd && OrigIter != OrigEnd; ++UsedIter, ++OrigIter) { if (*UsedIter < *OrigIter) return true; if (*UsedIter > *OrigIter) break; } // TODO: Add a different warning which will print the field names. HandleDeclRefExpr(DRE); return true; } // For most expressions, the cast is directly above the DeclRefExpr. // For conditional operators, the cast can be outside the conditional // operator if both expressions are DeclRefExpr's. void HandleValue(Expr *E) { E = E->IgnoreParens(); if (DeclRefExpr* DRE = dyn_cast(E)) { HandleDeclRefExpr(DRE); return; } if (ConditionalOperator *CO = dyn_cast(E)) { Visit(CO->getCond()); HandleValue(CO->getTrueExpr()); HandleValue(CO->getFalseExpr()); return; } if (BinaryConditionalOperator *BCO = dyn_cast(E)) { Visit(BCO->getCond()); HandleValue(BCO->getFalseExpr()); return; } if (OpaqueValueExpr *OVE = dyn_cast(E)) { HandleValue(OVE->getSourceExpr()); return; } if (BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_Comma) { Visit(BO->getLHS()); HandleValue(BO->getRHS()); return; } } if (isa(E)) { if (isInitList) { if (CheckInitListMemberExpr(cast(E), false /*CheckReference*/)) return; } Expr *Base = E->IgnoreParenImpCasts(); while (MemberExpr *ME = dyn_cast(Base)) { // Check for static member variables and don't warn on them. if (!isa(ME->getMemberDecl())) return; Base = ME->getBase()->IgnoreParenImpCasts(); } if (DeclRefExpr *DRE = dyn_cast(Base)) HandleDeclRefExpr(DRE); return; } Visit(E); } // Reference types not handled in HandleValue are handled here since all // uses of references are bad, not just r-value uses. void VisitDeclRefExpr(DeclRefExpr *E) { if (isReferenceType) HandleDeclRefExpr(E); } void VisitImplicitCastExpr(ImplicitCastExpr *E) { if (E->getCastKind() == CK_LValueToRValue) { HandleValue(E->getSubExpr()); return; } Inherited::VisitImplicitCastExpr(E); } void VisitMemberExpr(MemberExpr *E) { if (isInitList) { if (CheckInitListMemberExpr(E, true /*CheckReference*/)) return; } // Don't warn on arrays since they can be treated as pointers. if (E->getType()->canDecayToPointerType()) return; // Warn when a non-static method call is followed by non-static member // field accesses, which is followed by a DeclRefExpr. CXXMethodDecl *MD = dyn_cast(E->getMemberDecl()); bool Warn = (MD && !MD->isStatic()); Expr *Base = E->getBase()->IgnoreParenImpCasts(); while (MemberExpr *ME = dyn_cast(Base)) { if (!isa(ME->getMemberDecl())) Warn = false; Base = ME->getBase()->IgnoreParenImpCasts(); } if (DeclRefExpr *DRE = dyn_cast(Base)) { if (Warn) HandleDeclRefExpr(DRE); return; } // The base of a MemberExpr is not a MemberExpr or a DeclRefExpr. // Visit that expression. Visit(Base); } void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { Expr *Callee = E->getCallee(); if (isa(Callee)) return Inherited::VisitCXXOperatorCallExpr(E); Visit(Callee); for (auto Arg: E->arguments()) HandleValue(Arg->IgnoreParenImpCasts()); } void VisitUnaryOperator(UnaryOperator *E) { // For POD record types, addresses of its own members are well-defined. if (E->getOpcode() == UO_AddrOf && isRecordType && isa(E->getSubExpr()->IgnoreParens())) { if (!isPODType) HandleValue(E->getSubExpr()); return; } if (E->isIncrementDecrementOp()) { HandleValue(E->getSubExpr()); return; } Inherited::VisitUnaryOperator(E); } void VisitObjCMessageExpr(ObjCMessageExpr *E) {} void VisitCXXConstructExpr(CXXConstructExpr *E) { if (E->getConstructor()->isCopyConstructor()) { Expr *ArgExpr = E->getArg(0); if (InitListExpr *ILE = dyn_cast(ArgExpr)) if (ILE->getNumInits() == 1) ArgExpr = ILE->getInit(0); if (ImplicitCastExpr *ICE = dyn_cast(ArgExpr)) if (ICE->getCastKind() == CK_NoOp) ArgExpr = ICE->getSubExpr(); HandleValue(ArgExpr); return; } Inherited::VisitCXXConstructExpr(E); } void VisitCallExpr(CallExpr *E) { // Treat std::move as a use. if (E->getNumArgs() == 1) { if (FunctionDecl *FD = E->getDirectCallee()) { if (FD->isInStdNamespace() && FD->getIdentifier() && FD->getIdentifier()->isStr("move")) { HandleValue(E->getArg(0)); return; } } } Inherited::VisitCallExpr(E); } void VisitBinaryOperator(BinaryOperator *E) { if (E->isCompoundAssignmentOp()) { HandleValue(E->getLHS()); Visit(E->getRHS()); return; } Inherited::VisitBinaryOperator(E); } // A custom visitor for BinaryConditionalOperator is needed because the // regular visitor would check the condition and true expression separately // but both point to the same place giving duplicate diagnostics. void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { Visit(E->getCond()); Visit(E->getFalseExpr()); } void HandleDeclRefExpr(DeclRefExpr *DRE) { Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; unsigned diag; if (isReferenceType) { diag = diag::warn_uninit_self_reference_in_reference_init; } else if (cast(OrigDecl)->isStaticLocal()) { diag = diag::warn_static_self_reference_in_init; } else if (isa(OrigDecl->getDeclContext()) || isa(OrigDecl->getDeclContext()) || DRE->getDecl()->getType()->isRecordType()) { diag = diag::warn_uninit_self_reference_in_init; } else { // Local variables will be handled by the CFG analysis. return; } S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, S.PDiag(diag) << DRE->getNameInfo().getName() << OrigDecl->getLocation() << DRE->getSourceRange()); } }; /// CheckSelfReference - Warns if OrigDecl is used in expression E. static void CheckSelfReference(Sema &S, Decl* OrigDecl, Expr *E, bool DirectInit) { // Parameters arguments are occassionially constructed with itself, // for instance, in recursive functions. Skip them. if (isa(OrigDecl)) return; E = E->IgnoreParens(); // Skip checking T a = a where T is not a record or reference type. // Doing so is a way to silence uninitialized warnings. if (!DirectInit && !cast(OrigDecl)->getType()->isRecordType()) if (ImplicitCastExpr *ICE = dyn_cast(E)) if (ICE->getCastKind() == CK_LValueToRValue) if (DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr())) if (DRE->getDecl() == OrigDecl) return; SelfReferenceChecker(S, OrigDecl).CheckExpr(E); } } // end anonymous namespace namespace { // Simple wrapper to add the name of a variable or (if no variable is // available) a DeclarationName into a diagnostic. struct VarDeclOrName { VarDecl *VDecl; DeclarationName Name; friend const Sema::SemaDiagnosticBuilder & operator<<(const Sema::SemaDiagnosticBuilder &Diag, VarDeclOrName VN) { return VN.VDecl ? Diag << VN.VDecl : Diag << VN.Name; } }; } // end anonymous namespace QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, QualType Type, TypeSourceInfo *TSI, SourceRange Range, bool DirectInit, Expr *Init) { bool IsInitCapture = !VDecl; assert((!VDecl || !VDecl->isInitCapture()) && "init captures are expected to be deduced prior to initialization"); VarDeclOrName VN{VDecl, Name}; DeducedType *Deduced = Type->getContainedDeducedType(); assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); // C++11 [dcl.spec.auto]p3 if (!Init) { assert(VDecl && "no init for init capture deduction?"); Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) << VDecl->getDeclName() << Type; return QualType(); } ArrayRef DeduceInits = Init; if (DirectInit) { if (auto *PL = dyn_cast_or_null(Init)) DeduceInits = PL->exprs(); } if (isa(Deduced)) { assert(VDecl && "non-auto type for init capture deduction?"); InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); InitializationKind Kind = InitializationKind::CreateForInit( VDecl->getLocation(), DirectInit, Init); // FIXME: Initialization should not be taking a mutable list of inits. SmallVector InitsCopy(DeduceInits.begin(), DeduceInits.end()); return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, InitsCopy); } if (DirectInit) { if (auto *IL = dyn_cast(Init)) DeduceInits = IL->inits(); } // Deduction only works if we have exactly one source expression. if (DeduceInits.empty()) { // It isn't possible to write this directly, but it is possible to // end up in this situation with "auto x(some_pack...);" Diag(Init->getLocStart(), IsInitCapture ? diag::err_init_capture_no_expression : diag::err_auto_var_init_no_expression) << VN << Type << Range; return QualType(); } if (DeduceInits.size() > 1) { Diag(DeduceInits[1]->getLocStart(), IsInitCapture ? diag::err_init_capture_multiple_expressions : diag::err_auto_var_init_multiple_expressions) << VN << Type << Range; return QualType(); } Expr *DeduceInit = DeduceInits[0]; if (DirectInit && isa(DeduceInit)) { Diag(Init->getLocStart(), IsInitCapture ? diag::err_init_capture_paren_braces : diag::err_auto_var_init_paren_braces) << isa(Init) << VN << Type << Range; return QualType(); } // Expressions default to 'id' when we're in a debugger. bool DefaultedAnyToId = false; if (getLangOpts().DebuggerCastResultToId && Init->getType() == Context.UnknownAnyTy && !IsInitCapture) { ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType()); if (Result.isInvalid()) { return QualType(); } Init = Result.get(); DefaultedAnyToId = true; } // C++ [dcl.decomp]p1: // If the assignment-expression [...] has array type A and no ref-qualifier // is present, e has type cv A if (VDecl && isa(VDecl) && Context.hasSameUnqualifiedType(Type, Context.getAutoDeductType()) && DeduceInit->getType()->isConstantArrayType()) return Context.getQualifiedType(DeduceInit->getType(), Type.getQualifiers()); QualType DeducedType; if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) { if (!IsInitCapture) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); else if (isa(Init)) Diag(Range.getBegin(), diag::err_init_capture_deduction_failure_from_init_list) << VN << (DeduceInit->getType().isNull() ? TSI->getType() : DeduceInit->getType()) << DeduceInit->getSourceRange(); else Diag(Range.getBegin(), diag::err_init_capture_deduction_failure) << VN << TSI->getType() << (DeduceInit->getType().isNull() ? TSI->getType() : DeduceInit->getType()) << DeduceInit->getSourceRange(); } // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using // 'id' instead of a specific object type prevents most of our usual // checks. // We only want to warn outside of template instantiations, though: // inside a template, the 'id' could have come from a parameter. if (!inTemplateInstantiation() && !DefaultedAnyToId && !IsInitCapture && !DeducedType.isNull() && DeducedType->isObjCIdType()) { SourceLocation Loc = TSI->getTypeLoc().getBeginLoc(); Diag(Loc, diag::warn_auto_var_is_id) << VN << Range; } return DeducedType; } bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, Expr *Init) { QualType DeducedType = deduceVarTypeFromInitializer( VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init); if (DeducedType.isNull()) { VDecl->setInvalidDecl(); return true; } VDecl->setType(DeducedType); assert(VDecl->isLinkageValid()); // In ARC, infer lifetime. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) VDecl->setInvalidDecl(); // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDecl()) { // We never need to merge the type, because we cannot form an incomplete // array of auto, nor deduce such a type. MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false); } // Check the deduced type is valid for a variable declaration. CheckVariableDeclarationType(VDecl); return VDecl->isInvalidDecl(); } /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. if (!RealDecl || RealDecl->isInvalidDecl()) { CorrectDelayedTyposInExpr(Init, dyn_cast_or_null(RealDecl)); return; } if (CXXMethodDecl *Method = dyn_cast(RealDecl)) { // Pure-specifiers are handled in ActOnPureSpecifier. Diag(Method->getLocation(), diag::err_member_function_initialization) << Method->getDeclName() << Init->getSourceRange(); Method->setInvalidDecl(); return; } VarDecl *VDecl = dyn_cast(RealDecl); if (!VDecl) { assert(!isa(RealDecl) && "field init shouldn't get here"); Diag(RealDecl->getLocation(), diag::err_illegal_initializer); RealDecl->setInvalidDecl(); return; } // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (VDecl->getType()->isUndeducedType()) { // Attempt typo correction early so that the type of the init expression can // be deduced based on the chosen correction if the original init contains a // TypoExpr. ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl); if (!Res.isUsable()) { RealDecl->setInvalidDecl(); return; } Init = Res.get(); if (DeduceVariableDeclarationType(VDecl, DirectInit, Init)) return; } // dllimport cannot be used on variable definitions. if (VDecl->hasAttr() && !VDecl->isStaticDataMember()) { Diag(VDecl->getLocation(), diag::err_attribute_dllimport_data_definition); VDecl->setInvalidDecl(); return; } if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) { // C99 6.7.8p5. C++ has no such restriction, but that is a defect. Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); return; } if (!VDecl->getType()->isDependentType()) { // A definition must end up with a complete type, which means it must be // complete with the restriction that an array type might be completed by // the initializer; note that later code assumes this restriction. QualType BaseDeclType = VDecl->getType(); if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType)) BaseDeclType = Array->getElementType(); if (RequireCompleteType(VDecl->getLocation(), BaseDeclType, diag::err_typecheck_decl_incomplete_type)) { RealDecl->setInvalidDecl(); return; } // The variable can not have an abstract class type. if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(), diag::err_abstract_type_in_decl, AbstractVariableType)) VDecl->setInvalidDecl(); } // If adding the initializer will turn this declaration into a definition, // and we already have a definition for this variable, diagnose or otherwise // handle the situation. VarDecl *Def; if ((Def = VDecl->getDefinition()) && Def != VDecl && (!VDecl->isStaticDataMember() || VDecl->isOutOfLine()) && !VDecl->isThisDeclarationADemotedDefinition() && checkVarDeclRedefinition(Def, VDecl)) return; if (getLangOpts().CPlusPlus) { // C++ [class.static.data]p4 // If a static data member is of const integral or const // enumeration type, its declaration in the class definition can // specify a constant-initializer which shall be an integral // constant expression (5.19). In that case, the member can appear // in integral constant expressions. The member shall still be // defined in a namespace scope if it is used in the program and the // namespace scope definition shall not contain an initializer. // // We already performed a redefinition check above, but for static // data members we also need to check whether there was an in-class // declaration with an initializer. if (VDecl->isStaticDataMember() && VDecl->getCanonicalDecl()->hasInit()) { Diag(Init->getExprLoc(), diag::err_static_data_member_reinitialization) << VDecl->getDeclName(); Diag(VDecl->getCanonicalDecl()->getInit()->getExprLoc(), diag::note_previous_initializer) << 0; return; } if (VDecl->hasLocalStorage()) getCurFunction()->setHasBranchProtectedScope(); if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) { VDecl->setInvalidDecl(); return; } } // OpenCL 1.1 6.5.2: "Variables allocated in the __local address space inside // a kernel function cannot be initialized." if (VDecl->getType().getAddressSpace() == LangAS::opencl_local) { Diag(VDecl->getLocation(), diag::err_local_cant_init); VDecl->setInvalidDecl(); return; } // Get the decls type and save a reference for later, since // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; // Expressions default to 'id' when we're in a debugger // and we are assigning it to a variable of Objective-C pointer type. if (getLangOpts().DebuggerCastResultToId && DclT->isObjCObjectPointerType() && Init->getType() == Context.UnknownAnyTy) { ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType()); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.get(); } // Perform the initialization. ParenListExpr *CXXDirectInit = dyn_cast(Init); if (!VDecl->isInvalidDecl()) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); InitializationKind Kind = InitializationKind::CreateForInit( VDecl->getLocation(), DirectInit, Init); MultiExprArg Args = Init; if (CXXDirectInit) Args = MultiExprArg(CXXDirectInit->getExprs(), CXXDirectInit->getNumExprs()); // Try to correct any TypoExprs in the initialization arguments. for (size_t Idx = 0; Idx < Args.size(); ++Idx) { ExprResult Res = CorrectDelayedTyposInExpr( Args[Idx], VDecl, [this, Entity, Kind](Expr *E) { InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E)); return Init.Failed() ? ExprError() : E; }); if (Res.isInvalid()) { VDecl->setInvalidDecl(); } else if (Res.get() != Args[Idx]) { Args[Idx] = Res.get(); } } if (VDecl->isInvalidDecl()) return; InitializationSequence InitSeq(*this, Entity, Kind, Args, /*TopLevelOfInitList=*/false, /*TreatUnavailableAsInvalid=*/false); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.getAs(); } // Check for self-references within variable initializers. // Variables declared within a function/method body (except for references) // are handled by a dataflow analysis. if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() || VDecl->getType()->isReferenceType()) { CheckSelfReference(*this, RealDecl, Init, DirectInit); } // If the type changed, it means we had an incomplete type that was // completed by the initializer. For example: // int ary[] = { 1, 3, 5 }; // "ary" transitions from an IncompleteArrayType to a ConstantArrayType. if (!VDecl->isInvalidDecl() && (DclT != SavT)) VDecl->setType(DclT); if (!VDecl->isInvalidDecl()) { checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); if (VDecl->hasAttr()) checkRetainCycles(VDecl, Init); // It is safe to assign a weak reference into a strong variable. // Although this code can still have problems: // id x = self.weakProp; // id y = self.weakProp; // we do not warn to warn spuriously when 'x' and 'y' are on separate // paths through the function. This should be revisited if // -Wrepeated-use-of-weak is made flow-sensitive. if ((VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong || VDecl->getType().isNonWeakInMRRWithObjCWeak(Context)) && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Init->getLocStart())) getCurFunction()->markSafeWeakUse(Init); } // The initialization is usually a full-expression. // // FIXME: If this is a braced initialization of an aggregate, it is not // an expression, and each individual field initializer is a separate // full-expression. For instance, in: // // struct Temp { ~Temp(); }; // struct S { S(Temp); }; // struct T { S a, b; } t = { Temp(), Temp() } // // we should destroy the first Temp before constructing the second. ExprResult Result = ActOnFinishFullExpr(Init, VDecl->getLocation(), false, VDecl->isConstexpr()); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.get(); // Attach the initializer to the decl. VDecl->setInit(Init); if (VDecl->isLocalVarDecl()) { // Don't check the initializer if the declaration is malformed. if (VDecl->isInvalidDecl()) { // do nothing // OpenCL v1.2 s6.5.3: __constant locals must be constant-initialized. // This is true even in OpenCL C++. } else if (VDecl->getType().getAddressSpace() == LangAS::opencl_constant) { CheckForConstantInitializer(Init, DclT); // Otherwise, C++ does not restrict the initializer. } else if (getLangOpts().CPlusPlus) { // do nothing // C99 6.7.8p4: All the expressions in an initializer for an object that has // static storage duration shall be constant expressions or string literals. } else if (VDecl->getStorageClass() == SC_Static) { CheckForConstantInitializer(Init, DclT); // C89 is stricter than C99 for aggregate initializers. // C89 6.5.7p3: All the expressions [...] in an initializer list // for an object that has aggregate or union type shall be // constant expressions. } else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() && isa(Init)) { const Expr *Culprit; if (!Init->isConstantInitializer(Context, false, &Culprit)) { Diag(Culprit->getExprLoc(), diag::ext_aggregate_init_not_constant) << Culprit->getSourceRange(); } } } else if (VDecl->isStaticDataMember() && !VDecl->isInline() && VDecl->getLexicalDeclContext()->isRecord()) { // This is an in-class initialization for a static data member, e.g., // // struct S { // static const int value = 17; // }; // C++ [class.mem]p4: // A member-declarator can contain a constant-initializer only // if it declares a static member (9.4) of const integral or // const enumeration type, see 9.4.2. // // C++11 [class.static.data]p3: // If a non-volatile non-inline const static data member is of integral // or enumeration type, its declaration in the class definition can // specify a brace-or-equal-initializer in which every initializer-clause // that is an assignment-expression is a constant expression. A static // data member of literal type can be declared in the class definition // with the constexpr specifier; if so, its declaration shall specify a // brace-or-equal-initializer in which every initializer-clause that is // an assignment-expression is a constant expression. // Do nothing on dependent types. if (DclT->isDependentType()) { // Allow any 'static constexpr' members, whether or not they are of literal // type. We separately check that every constexpr variable is of literal // type. } else if (VDecl->isConstexpr()) { // Require constness. } else if (!DclT.isConstQualified()) { Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const) << Init->getSourceRange(); VDecl->setInvalidDecl(); // We allow integer constant expressions in all cases. } else if (DclT->isIntegralOrEnumerationType()) { // Check whether the expression is a constant expression. SourceLocation Loc; if (getLangOpts().CPlusPlus11 && DclT.isVolatileQualified()) // In C++11, a non-constexpr const static data member with an // in-class initializer cannot be volatile. Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile); else if (Init->isValueDependent()) ; // Nothing to check. else if (Init->isIntegerConstantExpr(Context, &Loc)) ; // Ok, it's an ICE! else if (Init->isEvaluatable(Context)) { // If we can constant fold the initializer through heroics, accept it, // but report this as a use of an extension for -pedantic. Diag(Loc, diag::ext_in_class_initializer_non_constant) << Init->getSourceRange(); } else { // Otherwise, this is some crazy unknown case. Report the issue at the // location provided by the isIntegerConstantExpr failed check. Diag(Loc, diag::err_in_class_initializer_non_constant) << Init->getSourceRange(); VDecl->setInvalidDecl(); } // We allow foldable floating-point constants as an extension. } else if (DclT->isFloatingType()) { // also permits complex, which is ok // In C++98, this is a GNU extension. In C++11, it is not, but we support // it anyway and provide a fixit to add the 'constexpr'. if (getLangOpts().CPlusPlus11) { Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type_cxx11) << DclT << Init->getSourceRange(); Diag(VDecl->getLocStart(), diag::note_in_class_initializer_float_type_cxx11) << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); } else { Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) << DclT << Init->getSourceRange(); if (!Init->isValueDependent() && !Init->isEvaluatable(Context)) { Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant) << Init->getSourceRange(); VDecl->setInvalidDecl(); } } // Suggest adding 'constexpr' in C++11 for literal types. } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType(Context)) { Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type) << DclT << Init->getSourceRange() << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); VDecl->setConstexpr(true); } else { Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type) << DclT << Init->getSourceRange(); VDecl->setInvalidDecl(); } } else if (VDecl->isFileVarDecl()) { // In C, extern is typically used to avoid tentative definitions when // declaring variables in headers, but adding an intializer makes it a // defintion. This is somewhat confusing, so GCC and Clang both warn on it. // In C++, extern is often used to give implictly static const variables // external linkage, so don't warn in that case. If selectany is present, // this might be header code intended for C and C++ inclusion, so apply the // C++ rules. if (VDecl->getStorageClass() == SC_Extern && ((!getLangOpts().CPlusPlus && !VDecl->hasAttr()) || !Context.getBaseElementType(VDecl->getType()).isConstQualified()) && !(getLangOpts().CPlusPlus && VDecl->isExternC()) && !isTemplateInstantiation(VDecl->getTemplateSpecializationKind())) Diag(VDecl->getLocation(), diag::warn_extern_init); // C99 6.7.8p4. All file scoped initializers need to be constant. if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) CheckForConstantInitializer(Init, DclT); } // We will represent direct-initialization similarly to copy-initialization: // int x(1); -as-> int x = 1; // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c); // // Clients that want to distinguish between the two forms, can check for // direct initializer using VarDecl::getInitStyle(). // A major benefit is that clients that don't particularly care about which // exactly form was it (like the CodeGen) can handle both cases without // special case code. // C++ 8.5p11: // The form of initialization (using parentheses or '=') is generally // insignificant, but does matter when the entity being initialized has a // class type. if (CXXDirectInit) { assert(DirectInit && "Call-style initializer must be direct init."); VDecl->setInitStyle(VarDecl::CallInit); } else if (DirectInit) { // This must be list-initialization. No other way is direct-initialization. VDecl->setInitStyle(VarDecl::ListInit); } CheckCompleteVariableDeclaration(VDecl); } /// ActOnInitializerError - Given that there was an error parsing an /// initializer for the given declaration, try to return to some form /// of sanity. void Sema::ActOnInitializerError(Decl *D) { // Our main concern here is re-establishing invariants like "a // variable's type is either dependent or complete". if (!D || D->isInvalidDecl()) return; VarDecl *VD = dyn_cast(D); if (!VD) return; // Bindings are not usable if we can't make sense of the initializer. if (auto *DD = dyn_cast(D)) for (auto *BD : DD->bindings()) BD->setInvalidDecl(); // Auto types are meaningless if we can't make sense of the initializer. if (ParsingInitForAutoVars.count(D)) { D->setInvalidDecl(); return; } QualType Ty = VD->getType(); if (Ty->isDependentType()) return; // Require a complete type. if (RequireCompleteType(VD->getLocation(), Context.getBaseElementType(Ty), diag::err_typecheck_decl_incomplete_type)) { VD->setInvalidDecl(); return; } // Require a non-abstract type. if (RequireNonAbstractType(VD->getLocation(), Ty, diag::err_abstract_type_in_decl, AbstractVariableType)) { VD->setInvalidDecl(); return; } // Don't bother complaining about constructors or destructors, // though. } void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // If there is no declaration, there was an error parsing it. Just ignore it. if (!RealDecl) return; if (VarDecl *Var = dyn_cast(RealDecl)) { QualType Type = Var->getType(); // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory. if (isa(RealDecl)) { Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var; Var->setInvalidDecl(); return; } if (Type->isUndeducedType() && DeduceVariableDeclarationType(Var, false, nullptr)) return; // C++11 [class.static.data]p3: A static data member can be declared with // the constexpr specifier; if so, its declaration shall specify // a brace-or-equal-initializer. // C++11 [dcl.constexpr]p1: The constexpr specifier shall be applied only to // the definition of a variable [...] or the declaration of a static data // member. if (Var->isConstexpr() && !Var->isThisDeclarationADefinition() && !Var->isThisDeclarationADemotedDefinition()) { if (Var->isStaticDataMember()) { // C++1z removes the relevant rule; the in-class declaration is always // a definition there. if (!getLangOpts().CPlusPlus1z) { Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init) << Var->getDeclName(); Var->setInvalidDecl(); return; } } else { Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl); Var->setInvalidDecl(); return; } } // C++ Concepts TS [dcl.spec.concept]p1: [...] A variable template // definition having the concept specifier is called a variable concept. A // concept definition refers to [...] a variable concept and its initializer. if (VarTemplateDecl *VTD = Var->getDescribedVarTemplate()) { if (VTD->isConcept()) { Diag(Var->getLocation(), diag::err_var_concept_not_initialized); Var->setInvalidDecl(); return; } } // OpenCL v1.1 s6.5.3: variables declared in the constant address space must // be initialized. if (!Var->isInvalidDecl() && Var->getType().getAddressSpace() == LangAS::opencl_constant && Var->getStorageClass() != SC_Extern && !Var->getInit()) { Diag(Var->getLocation(), diag::err_opencl_constant_no_init); Var->setInvalidDecl(); return; } switch (Var->isThisDeclarationADefinition()) { case VarDecl::Definition: if (!Var->isStaticDataMember() || !Var->getAnyInitializer()) break; // We have an out-of-line definition of a static data member // that has an in-class initializer, so we type-check this like // a declaration. // // Fall through case VarDecl::DeclarationOnly: // It's only a declaration. // Block scope. C99 6.7p7: If an identifier for an object is // declared with no linkage (C99 6.2.2p6), the type for the // object shall be complete. if (!Type->isDependentType() && Var->isLocalVarDecl() && !Var->hasLinkage() && !Var->isInvalidDecl() && RequireCompleteType(Var->getLocation(), Type, diag::err_typecheck_decl_incomplete_type)) Var->setInvalidDecl(); // Make sure that the type is not abstract. if (!Type->isDependentType() && !Var->isInvalidDecl() && RequireNonAbstractType(Var->getLocation(), Type, diag::err_abstract_type_in_decl, AbstractVariableType)) Var->setInvalidDecl(); if (!Type->isDependentType() && !Var->isInvalidDecl() && Var->getStorageClass() == SC_PrivateExtern) { Diag(Var->getLocation(), diag::warn_private_extern); Diag(Var->getLocation(), diag::note_private_extern); } return; case VarDecl::TentativeDefinition: // File scope. C99 6.9.2p2: A declaration of an identifier for an // object that has file scope without an initializer, and without a // storage-class specifier or with the storage-class specifier "static", // constitutes a tentative definition. Note: A tentative definition with // external linkage is valid (C99 6.2.2p5). if (!Var->isInvalidDecl()) { if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(Type)) { if (RequireCompleteType(Var->getLocation(), ArrayT->getElementType(), diag::err_illegal_decl_array_incomplete_type)) Var->setInvalidDecl(); } else if (Var->getStorageClass() == SC_Static) { // C99 6.9.2p3: If the declaration of an identifier for an object is // a tentative definition and has internal linkage (C99 6.2.2p3), the // declared type shall not be an incomplete type. // NOTE: code such as the following // static struct s; // struct s { int a; }; // is accepted by gcc. Hence here we issue a warning instead of // an error and we do not invalidate the static declaration. // NOTE: to avoid multiple warnings, only check the first declaration. if (Var->isFirstDecl()) RequireCompleteType(Var->getLocation(), Type, diag::ext_typecheck_decl_incomplete_type); } } // Record the tentative definition; we're done. if (!Var->isInvalidDecl()) TentativeDefinitions.push_back(Var); return; } // Provide a specific diagnostic for uninitialized variable // definitions with incomplete array type. if (Type->isIncompleteArrayType()) { Diag(Var->getLocation(), diag::err_typecheck_incomplete_array_needs_initializer); Var->setInvalidDecl(); return; } // Provide a specific diagnostic for uninitialized variable // definitions with reference type. if (Type->isReferenceType()) { Diag(Var->getLocation(), diag::err_reference_var_requires_init) << Var->getDeclName() << SourceRange(Var->getLocation(), Var->getLocation()); Var->setInvalidDecl(); return; } // Do not attempt to type-check the default initializer for a // variable with dependent type. if (Type->isDependentType()) return; if (Var->isInvalidDecl()) return; if (!Var->hasAttr()) { if (RequireCompleteType(Var->getLocation(), Context.getBaseElementType(Type), diag::err_typecheck_decl_incomplete_type)) { Var->setInvalidDecl(); return; } } else { return; } // The variable can not have an abstract class type. if (RequireNonAbstractType(Var->getLocation(), Type, diag::err_abstract_type_in_decl, AbstractVariableType)) { Var->setInvalidDecl(); return; } // Check for jumps past the implicit initializer. C++0x // clarifies that this applies to a "variable with automatic // storage duration", not a "local variable". // C++11 [stmt.dcl]p3 // A program that jumps from a point where a variable with automatic // storage duration is not in scope to a point where it is in scope is // ill-formed unless the variable has scalar type, class type with a // trivial default constructor and a trivial destructor, a cv-qualified // version of one of these types, or an array of one of the preceding // types and is declared without an initializer. if (getLangOpts().CPlusPlus && Var->hasLocalStorage()) { if (const RecordType *Record = Context.getBaseElementType(Type)->getAs()) { CXXRecordDecl *CXXRecord = cast(Record->getDecl()); // Mark the function for further checking even if the looser rules of // C++11 do not require such checks, so that we can diagnose // incompatibilities with C++98. if (!CXXRecord->isPOD()) getCurFunction()->setHasBranchProtectedScope(); } } // C++03 [dcl.init]p9: // If no initializer is specified for an object, and the // object is of (possibly cv-qualified) non-POD class type (or // array thereof), the object shall be default-initialized; if // the object is of const-qualified type, the underlying class // type shall have a user-declared default // constructor. Otherwise, if no initializer is specified for // a non- static object, the object and its subobjects, if // any, have an indeterminate initial value); if the object // or any of its subobjects are of const-qualified type, the // program is ill-formed. // C++0x [dcl.init]p11: // If no initializer is specified for an object, the object is // default-initialized; [...]. InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); InitializationKind Kind = InitializationKind::CreateDefault(Var->getLocation()); InitializationSequence InitSeq(*this, Entity, Kind, None); ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None); if (Init.isInvalid()) Var->setInvalidDecl(); else if (Init.get()) { Var->setInit(MaybeCreateExprWithCleanups(Init.get())); // This is important for template substitution. Var->setInitStyle(VarDecl::CallInit); } CheckCompleteVariableDeclaration(Var); } } void Sema::ActOnCXXForRangeDecl(Decl *D) { // If there is no declaration, there was an error parsing it. Ignore it. if (!D) return; VarDecl *VD = dyn_cast(D); if (!VD) { Diag(D->getLocation(), diag::err_for_range_decl_must_be_var); D->setInvalidDecl(); return; } VD->setCXXForRangeDecl(true); // for-range-declaration cannot be given a storage class specifier. int Error = -1; switch (VD->getStorageClass()) { case SC_None: break; case SC_Extern: Error = 0; break; case SC_Static: Error = 1; break; case SC_PrivateExtern: Error = 2; break; case SC_Auto: Error = 3; break; case SC_Register: Error = 4; break; } if (Error != -1) { Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class) << VD->getDeclName() << Error; D->setInvalidDecl(); } } StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, ParsedAttributes &Attrs, SourceLocation AttrEnd) { // C++1y [stmt.iter]p1: // A range-based for statement of the form // for ( for-range-identifier : for-range-initializer ) statement // is equivalent to // for ( auto&& for-range-identifier : for-range-initializer ) statement DeclSpec DS(Attrs.getPool().getFactory()); const char *PrevSpec; unsigned DiagID; DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID, getPrintingPolicy()); Declarator D(DS, Declarator::ForContext); D.SetIdentifier(Ident, IdentLoc); D.takeAttributes(Attrs, AttrEnd); ParsedAttributes EmptyAttrs(Attrs.getPool().getFactory()); D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/false), EmptyAttrs, IdentLoc); Decl *Var = ActOnDeclarator(S, D); cast(Var)->setCXXForRangeDecl(true); FinalizeDeclaration(Var); return ActOnDeclStmt(FinalizeDeclaratorGroup(S, DS, Var), IdentLoc, AttrEnd.isValid() ? AttrEnd : IdentLoc); } void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; if (getLangOpts().OpenCL) { // OpenCL v2.0 s6.12.5 - Every block variable declaration must have an // initialiser if (var->getTypeSourceInfo()->getType()->isBlockPointerType() && !var->hasInit()) { Diag(var->getLocation(), diag::err_opencl_invalid_block_declaration) << 1 /*Init*/; var->setInvalidDecl(); return; } } // In Objective-C, don't allow jumps past the implicit initialization of a // local retaining variable. if (getLangOpts().ObjC1 && var->hasLocalStorage()) { switch (var->getType().getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: break; case Qualifiers::OCL_Weak: case Qualifiers::OCL_Strong: getCurFunction()->setHasBranchProtectedScope(); break; } } // Warn about externally-visible variables being defined without a // prior declaration. We only want to do this for global // declarations, but we also specifically need to avoid doing it for // class members because the linkage of an anonymous class can // change if it's later given a typedef name. if (var->isThisDeclarationADefinition() && var->getDeclContext()->getRedeclContext()->isFileContext() && var->isExternallyVisible() && var->hasLinkage() && !getDiagnostics().isIgnored(diag::warn_missing_variable_declarations, var->getLocation())) { // Find a previous declaration that's not a definition. VarDecl *prev = var->getPreviousDecl(); while (prev && prev->isThisDeclarationADefinition()) prev = prev->getPreviousDecl(); if (!prev) Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var; } // Cache the result of checking for constant initialization. Optional CacheHasConstInit; const Expr *CacheCulprit; auto checkConstInit = [&]() mutable { if (!CacheHasConstInit) CacheHasConstInit = var->getInit()->isConstantInitializer( Context, var->getType()->isReferenceType(), &CacheCulprit); return *CacheHasConstInit; }; if (var->getTLSKind() == VarDecl::TLS_Static) { if (var->getType().isDestructedType()) { // GNU C++98 edits for __thread, [basic.start.term]p3: // The type of an object with thread storage duration shall not // have a non-trivial destructor. Diag(var->getLocation(), diag::err_thread_nontrivial_dtor); if (getLangOpts().CPlusPlus11) Diag(var->getLocation(), diag::note_use_thread_local); } else if (getLangOpts().CPlusPlus && var->hasInit()) { if (!checkConstInit()) { // GNU C++98 edits for __thread, [basic.start.init]p4: // An object of thread storage duration shall not require dynamic // initialization. // FIXME: Need strict checking here. Diag(CacheCulprit->getExprLoc(), diag::err_thread_dynamic_init) << CacheCulprit->getSourceRange(); if (getLangOpts().CPlusPlus11) Diag(var->getLocation(), diag::note_use_thread_local); } } } // Apply section attributes and pragmas to global variables. bool GlobalStorage = var->hasGlobalStorage(); if (GlobalStorage && var->isThisDeclarationADefinition() && !inTemplateInstantiation()) { PragmaStack *Stack = nullptr; int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read; if (var->getType().isConstQualified()) Stack = &ConstSegStack; else if (!var->getInit()) { Stack = &BSSSegStack; SectionFlags |= ASTContext::PSF_Write; } else { Stack = &DataSegStack; SectionFlags |= ASTContext::PSF_Write; } if (Stack->CurrentValue && !var->hasAttr()) { var->addAttr(SectionAttr::CreateImplicit( Context, SectionAttr::Declspec_allocate, Stack->CurrentValue->getString(), Stack->CurrentPragmaLocation)); } if (const SectionAttr *SA = var->getAttr()) if (UnifySection(SA->getName(), SectionFlags, var)) var->dropAttr(); // Apply the init_seg attribute if this has an initializer. If the // initializer turns out to not be dynamic, we'll end up ignoring this // attribute. if (CurInitSeg && var->getInit()) var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(), CurInitSegLoc)); } // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) { // If this variable must be emitted, add it as an initializer for the // current module. if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty()) Context.addModuleInitializer(ModuleScopes.back().Module, var); return; } if (auto *DD = dyn_cast(var)) CheckCompleteDecompositionDeclaration(DD); QualType type = var->getType(); if (type->isDependentType()) return; // __block variables might require us to capture a copy-initializer. if (var->hasAttr()) { // It's currently invalid to ever have a __block variable with an // array type; should we diagnose that here? // Regardless, we don't want to ignore array nesting when // constructing this copy. if (type->isStructureOrClassType()) { EnterExpressionEvaluationContext scope( *this, ExpressionEvaluationContext::PotentiallyEvaluated); SourceLocation poi = var->getLocation(); Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi); ExprResult result = PerformMoveOrCopyInitialization( InitializedEntity::InitializeBlock(poi, type, false), var, var->getType(), varRef, /*AllowNRVO=*/true); if (!result.isInvalid()) { result = MaybeCreateExprWithCleanups(result); Expr *init = result.getAs(); Context.setBlockVarCopyInits(var, init); } } } Expr *Init = var->getInit(); bool IsGlobal = GlobalStorage && !var->isStaticLocal(); QualType baseType = Context.getBaseElementType(type); if (!var->getDeclContext()->isDependentContext() && Init && !Init->isValueDependent()) { if (var->isConstexpr()) { SmallVector Notes; if (!var->evaluateValue(Notes) || !var->isInitICE()) { SourceLocation DiagLoc = var->getLocation(); // If the note doesn't add any useful information other than a source // location, fold it into the primary diagnostic. if (Notes.size() == 1 && Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr) { DiagLoc = Notes[0].first; Notes.clear(); } Diag(DiagLoc, diag::err_constexpr_var_requires_const_init) << var << Init->getSourceRange(); for (unsigned I = 0, N = Notes.size(); I != N; ++I) Diag(Notes[I].first, Notes[I].second); } } else if (var->isUsableInConstantExpressions(Context)) { // Check whether the initializer of a const variable of integral or // enumeration type is an ICE now, since we can't tell whether it was // initialized by a constant expression if we check later. var->checkInitIsICE(); } // Don't emit further diagnostics about constexpr globals since they // were just diagnosed. if (!var->isConstexpr() && GlobalStorage && var->hasAttr()) { // FIXME: Need strict checking in C++03 here. bool DiagErr = getLangOpts().CPlusPlus11 ? !var->checkInitIsICE() : !checkConstInit(); if (DiagErr) { auto attr = var->getAttr(); Diag(var->getLocation(), diag::err_require_constant_init_failed) << Init->getSourceRange(); Diag(attr->getLocation(), diag::note_declared_required_constant_init_here) << attr->getRange(); } } else if (!var->isConstexpr() && IsGlobal && !getDiagnostics().isIgnored(diag::warn_global_constructor, var->getLocation())) { // Warn about globals which don't have a constant initializer. Don't // warn about globals with a non-trivial destructor because we already // warned about them. CXXRecordDecl *RD = baseType->getAsCXXRecordDecl(); if (!(RD && !RD->hasTrivialDestructor())) { if (!checkConstInit()) Diag(var->getLocation(), diag::warn_global_constructor) << Init->getSourceRange(); } } } // Require the destructor. if (const RecordType *recordType = baseType->getAs()) FinalizeVarWithDestructor(var, recordType); // If this variable must be emitted, add it as an initializer for the current // module. if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty()) Context.addModuleInitializer(ModuleScopes.back().Module, var); } /// \brief Determines if a variable's alignment is dependent. static bool hasDependentAlignment(VarDecl *VD) { if (VD->getType()->isDependentType()) return true; for (auto *I : VD->specific_attrs()) if (I->isAlignmentDependent()) return true; return false; } /// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform /// any semantic actions necessary after any initializer has been attached. void Sema::FinalizeDeclaration(Decl *ThisDecl) { // Note that we are no longer parsing the initializer for this declaration. ParsingInitForAutoVars.erase(ThisDecl); VarDecl *VD = dyn_cast_or_null(ThisDecl); if (!VD) return; if (auto *DD = dyn_cast(ThisDecl)) { for (auto *BD : DD->bindings()) { FinalizeDeclaration(BD); } } checkAttributesAfterMerging(*this, *VD); // Perform TLS alignment check here after attributes attached to the variable // which may affect the alignment have been processed. Only perform the check // if the target has a maximum TLS alignment (zero means no constraints). if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) { // Protect the check so that it's not performed on dependent types and // dependent alignments (we can't determine the alignment in that case). if (VD->getTLSKind() && !hasDependentAlignment(VD) && !VD->isInvalidDecl()) { CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign); if (Context.getDeclAlign(VD) > MaxAlignChars) { Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD << (unsigned)MaxAlignChars.getQuantity(); } } } if (VD->isStaticLocal()) { if (FunctionDecl *FD = dyn_cast_or_null(VD->getParentFunctionOrMethod())) { // Static locals inherit dll attributes from their function. if (Attr *A = getDLLAttr(FD)) { auto *NewAttr = cast(A->clone(getASTContext())); NewAttr->setInherited(true); VD->addAttr(NewAttr); } // CUDA E.2.9.4: Within the body of a __device__ or __global__ // function, only __shared__ variables may be declared with // static storage class. if (getLangOpts().CUDA && !VD->hasAttr() && CUDADiagIfDeviceCode(VD->getLocation(), diag::err_device_static_local_var) << CurrentCUDATarget()) VD->setInvalidDecl(); } } // Perform check for initializers of device-side global variables. // CUDA allows empty constructors as initializers (see E.2.3.1, CUDA // 7.5). We must also apply the same checks to all __shared__ // variables whether they are local or not. CUDA also allows // constant initializers for __constant__ and __device__ variables. if (getLangOpts().CUDA) { const Expr *Init = VD->getInit(); if (Init && VD->hasGlobalStorage()) { if (VD->hasAttr() || VD->hasAttr() || VD->hasAttr()) { assert(!VD->isStaticLocal() || VD->hasAttr()); bool AllowedInit = false; if (const CXXConstructExpr *CE = dyn_cast(Init)) AllowedInit = isEmptyCudaConstructor(VD->getLocation(), CE->getConstructor()); // We'll allow constant initializers even if it's a non-empty // constructor according to CUDA rules. This deviates from NVCC, // but allows us to handle things like constexpr constructors. if (!AllowedInit && (VD->hasAttr() || VD->hasAttr())) AllowedInit = VD->getInit()->isConstantInitializer( Context, VD->getType()->isReferenceType()); // Also make sure that destructor, if there is one, is empty. if (AllowedInit) if (CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl()) AllowedInit = isEmptyCudaDestructor(VD->getLocation(), RD->getDestructor()); if (!AllowedInit) { Diag(VD->getLocation(), VD->hasAttr() ? diag::err_shared_var_init : diag::err_dynamic_var_init) << Init->getSourceRange(); VD->setInvalidDecl(); } } else { // This is a host-side global variable. Check that the initializer is // callable from the host side. const FunctionDecl *InitFn = nullptr; if (const CXXConstructExpr *CE = dyn_cast(Init)) { InitFn = CE->getConstructor(); } else if (const CallExpr *CE = dyn_cast(Init)) { InitFn = CE->getDirectCallee(); } if (InitFn) { CUDAFunctionTarget InitFnTarget = IdentifyCUDATarget(InitFn); if (InitFnTarget != CFT_Host && InitFnTarget != CFT_HostDevice) { Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer) << InitFnTarget << InitFn; Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn; VD->setInvalidDecl(); } } } } } // Grab the dllimport or dllexport attribute off of the VarDecl. const InheritableAttr *DLLAttr = getDLLAttr(VD); // Imported static data members cannot be defined out-of-line. if (const auto *IA = dyn_cast_or_null(DLLAttr)) { if (VD->isStaticDataMember() && VD->isOutOfLine() && VD->isThisDeclarationADefinition()) { // We allow definitions of dllimport class template static data members // with a warning. CXXRecordDecl *Context = cast(VD->getFirstDecl()->getDeclContext()); bool IsClassTemplateMember = isa(Context) || Context->getDescribedClassTemplate(); Diag(VD->getLocation(), IsClassTemplateMember ? diag::warn_attribute_dllimport_static_field_definition : diag::err_attribute_dllimport_static_field_definition); Diag(IA->getLocation(), diag::note_attribute); if (!IsClassTemplateMember) VD->setInvalidDecl(); } } // dllimport/dllexport variables cannot be thread local, their TLS index // isn't exported with the variable. if (DLLAttr && VD->getTLSKind()) { auto *F = dyn_cast_or_null(VD->getParentFunctionOrMethod()); if (F && getDLLAttr(F)) { assert(VD->isStaticLocal()); // But if this is a static local in a dlimport/dllexport function, the // function will never be inlined, which means the var would never be // imported, so having it marked import/export is safe. } else { Diag(VD->getLocation(), diag::err_attribute_dll_thread_local) << VD << DLLAttr; VD->setInvalidDecl(); } } if (UsedAttr *Attr = VD->getAttr()) { if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) { Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr; VD->dropAttr(); } } const DeclContext *DC = VD->getDeclContext(); // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this variable. if (DC->getRedeclContext()->isFileContext() && VD->isExternallyVisible()) AddPushedVisibilityAttribute(VD); // FIXME: Warn on unused var template partial specializations. if (VD->isFileVarDecl() && !isa(VD)) MarkUnusedFileScopedDecl(VD); // Now we have parsed the initializer and can update the table of magic // tag values. if (!VD->hasAttr() || !VD->getType()->isIntegralOrEnumerationType()) return; for (const auto *I : ThisDecl->specific_attrs()) { const Expr *MagicValueExpr = VD->getInit(); if (!MagicValueExpr) { continue; } llvm::APSInt MagicValueInt; if (!MagicValueExpr->isIntegerConstantExpr(MagicValueInt, Context)) { Diag(I->getRange().getBegin(), diag::err_type_tag_for_datatype_not_ice) << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange(); continue; } if (MagicValueInt.getActiveBits() > 64) { Diag(I->getRange().getBegin(), diag::err_type_tag_for_datatype_too_large) << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange(); continue; } uint64_t MagicValue = MagicValueInt.getZExtValue(); RegisterTypeTagForDatatype(I->getArgumentKind(), MagicValue, I->getMatchingCType(), I->getLayoutCompatible(), I->getMustBeNull()); } } static bool hasDeducedAuto(DeclaratorDecl *DD) { auto *VD = dyn_cast(DD); return VD && !VD->getType()->hasAutoForTrailingReturnType(); } Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, ArrayRef Group) { SmallVector Decls; if (DS.isTypeSpecOwned()) Decls.push_back(DS.getRepAsDecl()); DeclaratorDecl *FirstDeclaratorInGroup = nullptr; DecompositionDecl *FirstDecompDeclaratorInGroup = nullptr; bool DiagnosedMultipleDecomps = false; DeclaratorDecl *FirstNonDeducedAutoInGroup = nullptr; bool DiagnosedNonDeducedAuto = false; for (unsigned i = 0, e = Group.size(); i != e; ++i) { if (Decl *D = Group[i]) { // For declarators, there are some additional syntactic-ish checks we need // to perform. if (auto *DD = dyn_cast(D)) { if (!FirstDeclaratorInGroup) FirstDeclaratorInGroup = DD; if (!FirstDecompDeclaratorInGroup) FirstDecompDeclaratorInGroup = dyn_cast(D); if (!FirstNonDeducedAutoInGroup && DS.hasAutoTypeSpec() && !hasDeducedAuto(DD)) FirstNonDeducedAutoInGroup = DD; if (FirstDeclaratorInGroup != DD) { // A decomposition declaration cannot be combined with any other // declaration in the same group. if (FirstDecompDeclaratorInGroup && !DiagnosedMultipleDecomps) { Diag(FirstDecompDeclaratorInGroup->getLocation(), diag::err_decomp_decl_not_alone) << FirstDeclaratorInGroup->getSourceRange() << DD->getSourceRange(); DiagnosedMultipleDecomps = true; } // A declarator that uses 'auto' in any way other than to declare a // variable with a deduced type cannot be combined with any other // declarator in the same group. if (FirstNonDeducedAutoInGroup && !DiagnosedNonDeducedAuto) { Diag(FirstNonDeducedAutoInGroup->getLocation(), diag::err_auto_non_deduced_not_alone) << FirstNonDeducedAutoInGroup->getType() ->hasAutoForTrailingReturnType() << FirstDeclaratorInGroup->getSourceRange() << DD->getSourceRange(); DiagnosedNonDeducedAuto = true; } } } Decls.push_back(D); } } if (DeclSpec::isDeclRep(DS.getTypeSpecType())) { if (TagDecl *Tag = dyn_cast_or_null(DS.getRepAsDecl())) { handleTagNumbering(Tag, S); if (FirstDeclaratorInGroup && !Tag->hasNameForLinkage() && getLangOpts().CPlusPlus) Context.addDeclaratorForUnnamedTagDecl(Tag, FirstDeclaratorInGroup); } } return BuildDeclaratorGroup(Decls); } /// BuildDeclaratorGroup - convert a list of declarations into a declaration /// group, performing any necessary semantic checking. Sema::DeclGroupPtrTy Sema::BuildDeclaratorGroup(MutableArrayRef Group) { // C++14 [dcl.spec.auto]p7: (DR1347) // If the type that replaces the placeholder type is not the same in each // deduction, the program is ill-formed. if (Group.size() > 1) { QualType Deduced; VarDecl *DeducedDecl = nullptr; for (unsigned i = 0, e = Group.size(); i != e; ++i) { VarDecl *D = dyn_cast(Group[i]); if (!D || D->isInvalidDecl()) break; DeducedType *DT = D->getType()->getContainedDeducedType(); if (!DT || DT->getDeducedType().isNull()) continue; if (Deduced.isNull()) { Deduced = DT->getDeducedType(); DeducedDecl = D; } else if (!Context.hasSameType(DT->getDeducedType(), Deduced)) { auto *AT = dyn_cast(DT); Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_auto_different_deductions) << (AT ? (unsigned)AT->getKeyword() : 3) << Deduced << DeducedDecl->getDeclName() << DT->getDeducedType() << D->getDeclName() << DeducedDecl->getInit()->getSourceRange() << D->getInit()->getSourceRange(); D->setInvalidDecl(); break; } } } ActOnDocumentableDecls(Group); return DeclGroupPtrTy::make( DeclGroupRef::Create(Context, Group.data(), Group.size())); } void Sema::ActOnDocumentableDecl(Decl *D) { ActOnDocumentableDecls(D); } void Sema::ActOnDocumentableDecls(ArrayRef Group) { // Don't parse the comment if Doxygen diagnostics are ignored. if (Group.empty() || !Group[0]) return; if (Diags.isIgnored(diag::warn_doc_param_not_found, Group[0]->getLocation()) && Diags.isIgnored(diag::warn_unknown_comment_command_name, Group[0]->getLocation())) return; if (Group.size() >= 2) { // This is a decl group. Normally it will contain only declarations // produced from declarator list. But in case we have any definitions or // additional declaration references: // 'typedef struct S {} S;' // 'typedef struct S *S;' // 'struct S *pS;' // FinalizeDeclaratorGroup adds these as separate declarations. Decl *MaybeTagDecl = Group[0]; if (MaybeTagDecl && isa(MaybeTagDecl)) { Group = Group.slice(1); } } // See if there are any new comments that are not attached to a decl. ArrayRef Comments = Context.getRawCommentList().getComments(); if (!Comments.empty() && !Comments.back()->isAttached()) { // There is at least one comment that not attached to a decl. // Maybe it should be attached to one of these decls? // // Note that this way we pick up not only comments that precede the // declaration, but also comments that *follow* the declaration -- thanks to // the lookahead in the lexer: we've consumed the semicolon and looked // ahead through comments. for (unsigned i = 0, e = Group.size(); i != e; ++i) Context.getCommentForDecl(Group[i], &PP); } } /// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() /// to introduce parameters into function prototype scope. Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. // C++03 [dcl.stc]p2 also permits 'auto'. StorageClass SC = SC_None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { SC = SC_Register; } else if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_auto) { SC = SC_Auto; } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); D.getMutableDeclSpec().ClearStorageClassSpecs(); } if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) << getLangOpts().CPlusPlus1z; if (DS.isConstexprSpecified()) Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr) << 0; if (DS.isConceptSpecified()) Diag(DS.getConceptSpecLoc(), diag::err_concept_wrong_decl_kind); DiagnoseFunctionSpecifiers(DS); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType parmDeclType = TInfo->getType(); if (getLangOpts().CPlusPlus) { // Check that there are no default arguments inside the type of this // parameter. CheckExtraCXXDefaultArguments(D); // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) << D.getCXXScopeSpec().getRange(); D.getCXXScopeSpec().clear(); } } // Ensure we have a valid name IdentifierInfo *II = nullptr; if (D.hasName()) { II = D.getIdentifier(); if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name) << GetNameForDeclarator(D).getName(); D.setInvalidType(true); } } // Check for redeclaration of parameters, e.g. int foo(int x, int x); if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); LookupName(R, S); if (R.isSingleResult()) { NamedDecl *PrevDecl = R.getFoundDecl(); if (PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); // Just pretend that we didn't see the previous declaration. PrevDecl = nullptr; } else if (S->isDeclScope(PrevDecl)) { Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); // Recover by removing the name II = nullptr; D.SetIdentifier(nullptr, D.getIdentifierLoc()); D.setInvalidType(true); } } } // Temporarily put parameter variables in the translation unit, not // the enclosing context. This prevents them from accidentally // looking like class members in C++. ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(), D.getLocStart(), D.getIdentifierLoc(), II, parmDeclType, TInfo, SC); if (D.isInvalidType()) New->setInvalidDecl(); assert(S->isFunctionPrototypeScope()); assert(S->getFunctionPrototypeDepth() >= 1); New->setScopeInfo(S->getFunctionPrototypeDepth() - 1, S->getNextFunctionPrototypeIndex()); // Add the parameter declaration into this scope. S->AddDecl(New); if (II) IdResolver.AddDecl(New); ProcessDeclAttributes(S, New, D); if (D.getDeclSpec().isModulePrivateSpecified()) Diag(New->getLocation(), diag::err_module_private_local) << 1 << New->getDeclName() << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); if (New->hasAttr()) { Diag(New->getLocation(), diag::err_block_on_nonlocal); } return New; } /// \brief Synthesizes a variable for a parameter arising from a /// typedef. ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T) { /* FIXME: setting StartLoc == Loc. Would it be worth to modify callers so as to provide proper source location for the unnamed parameters, embedding the parameter's type? */ ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, nullptr, T, Context.getTrivialTypeSourceInfo(T, Loc), SC_None, nullptr); Param->setImplicit(); return Param; } void Sema::DiagnoseUnusedParameters(ArrayRef Parameters) { // Don't diagnose unused-parameter errors in template instantiations; we // will already have done so in the template itself. if (inTemplateInstantiation()) return; for (const ParmVarDecl *Parameter : Parameters) { if (!Parameter->isReferenced() && Parameter->getDeclName() && !Parameter->hasAttr()) { Diag(Parameter->getLocation(), diag::warn_unused_parameter) << Parameter->getDeclName(); } } } void Sema::DiagnoseSizeOfParametersAndReturnValue( ArrayRef Parameters, QualType ReturnTy, NamedDecl *D) { if (LangOpts.NumLargeByValueCopy == 0) // No check. return; // Warn if the return value is pass-by-value and larger than the specified // threshold. if (!ReturnTy->isDependentType() && ReturnTy.isPODType(Context)) { unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity(); if (Size > LangOpts.NumLargeByValueCopy) Diag(D->getLocation(), diag::warn_return_value_size) << D->getDeclName() << Size; } // Warn if any parameter is pass-by-value and larger than the specified // threshold. for (const ParmVarDecl *Parameter : Parameters) { QualType T = Parameter->getType(); if (T->isDependentType() || !T.isPODType(Context)) continue; unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); if (Size > LangOpts.NumLargeByValueCopy) Diag(Parameter->getLocation(), diag::warn_parameter_size) << Parameter->getDeclName() << Size; } } ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, StorageClass SC) { // In ARC, infer a lifetime qualifier for appropriate parameter types. if (getLangOpts().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_None && T->isObjCLifetimeType()) { Qualifiers::ObjCLifetime lifetime; // Special cases for arrays: // - if it's const, use __unsafe_unretained // - otherwise, it's an error if (T->isArrayType()) { if (!T.isConstQualified()) { DelayedDiagnostics.add( sema::DelayedDiagnostic::makeForbiddenType( NameLoc, diag::err_arc_array_param_no_ownership, T, false)); } lifetime = Qualifiers::OCL_ExplicitNone; } else { lifetime = T->getObjCARCImplicitLifetime(); } T = Context.getLifetimeQualifiedType(T, lifetime); } ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, Context.getAdjustedParameterType(T), TSInfo, SC, nullptr); // Parameters can not be abstract class types. // For record types, this is done by the AbstractClassUsageDiagnoser once // the class has been completely parsed. if (!CurContext->isRecord() && RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl, AbstractParamType)) New->setInvalidDecl(); // Parameter declarators cannot be interface types. All ObjC objects are // passed by reference. if (T->isObjCObjectType()) { SourceLocation TypeEndLoc = getLocForEndOfToken(TSInfo->getTypeLoc().getLocEnd()); Diag(NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << T << FixItHint::CreateInsertion(TypeEndLoc, "*"); T = Context.getObjCObjectPointerType(T); New->setType(T); } // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have // an address space. if (T.getAddressSpace() != 0) { // OpenCL allows function arguments declared to be an array of a type // to be qualified with an address space. if (!(getLangOpts().OpenCL && T->isArrayType())) { Diag(NameLoc, diag::err_arg_with_address_space); New->setInvalidDecl(); } } return New; } void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls) { DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' // for a K&R function. if (!FTI.hasPrototype) { for (int i = FTI.NumParams; i != 0; /* decrement in loop */) { --i; if (FTI.Params[i].Param == nullptr) { SmallString<256> Code; llvm::raw_svector_ostream(Code) << " int " << FTI.Params[i].Ident->getName() << ";\n"; Diag(FTI.Params[i].IdentLoc, diag::ext_param_not_declared) << FTI.Params[i].Ident << FixItHint::CreateInsertion(LocAfterDecls, Code); // Implicitly declare the argument as type 'int' for lack of a better // type. AttributeFactory attrs; DeclSpec DS(attrs); const char* PrevSpec; // unused unsigned DiagID; // unused DS.SetTypeSpecType(DeclSpec::TST_int, FTI.Params[i].IdentLoc, PrevSpec, DiagID, Context.getPrintingPolicy()); // Use the identifier location for the type source range. DS.SetRangeStart(FTI.Params[i].IdentLoc); DS.SetRangeEnd(FTI.Params[i].IdentLoc); Declarator ParamD(DS, Declarator::KNRTypeListContext); ParamD.SetIdentifier(FTI.Params[i].Ident, FTI.Params[i].IdentLoc); FTI.Params[i].Param = ActOnParamDeclarator(S, ParamD); } } } } Decl * Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) { assert(getCurFunctionDecl() == nullptr && "Function parsing confused"); assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); } void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) { Consumer.HandleInlineFunctionDefinition(D); } static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, const FunctionDecl*& PossibleZeroParamPrototype) { // Don't warn about invalid declarations. if (FD->isInvalidDecl()) return false; // Or declarations that aren't global. if (!FD->isGlobal()) return false; // Don't warn about C++ member functions. if (isa(FD)) return false; // Don't warn about 'main'. if (FD->isMain()) return false; // Don't warn about inline functions. if (FD->isInlined()) return false; // Don't warn about function templates. if (FD->getDescribedFunctionTemplate()) return false; // Don't warn about function template specializations. if (FD->isFunctionTemplateSpecialization()) return false; // Don't warn for OpenCL kernels. if (FD->hasAttr()) return false; // Don't warn on explicitly deleted functions. if (FD->isDeleted()) return false; bool MissingPrototype = true; for (const FunctionDecl *Prev = FD->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) { // Ignore any declarations that occur in function or method // scope, because they aren't visible from the header. if (Prev->getLexicalDeclContext()->isFunctionOrMethod()) continue; MissingPrototype = !Prev->getType()->isFunctionProtoType(); if (FD->getNumParams() == 0) PossibleZeroParamPrototype = Prev; break; } return MissingPrototype; } void Sema::CheckForFunctionRedefinition(FunctionDecl *FD, const FunctionDecl *EffectiveDefinition, SkipBodyInfo *SkipBody) { const FunctionDecl *Definition = EffectiveDefinition; if (!Definition) if (!FD->isDefined(Definition)) return; if (canRedefineFunction(Definition, getLangOpts())) return; // Don't emit an error when this is redifinition of a typo-corrected // definition. if (TypoCorrectedFunctionDefinitions.count(Definition)) return; // If we don't have a visible definition of the function, and it's inline or // a template, skip the new definition. if (SkipBody && !hasVisibleDefinition(Definition) && (Definition->getFormalLinkage() == InternalLinkage || Definition->isInlined() || Definition->getDescribedFunctionTemplate() || Definition->getNumTemplateParameterLists())) { SkipBody->ShouldSkip = true; if (auto *TD = Definition->getDescribedFunctionTemplate()) makeMergedDefinitionVisible(TD); makeMergedDefinitionVisible(const_cast(Definition)); return; } if (getLangOpts().GNUMode && Definition->isInlineSpecified() && Definition->getStorageClass() == SC_Extern) Diag(FD->getLocation(), diag::err_redefinition_extern_inline) << FD->getDeclName() << getLangOpts().CPlusPlus; else Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); Diag(Definition->getLocation(), diag::note_previous_definition); FD->setInvalidDecl(); } static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, Sema &S) { CXXRecordDecl *const LambdaClass = CallOperator->getParent(); LambdaScopeInfo *LSI = S.PushLambdaScope(); LSI->CallOperator = CallOperator; LSI->Lambda = LambdaClass; LSI->ReturnType = CallOperator->getReturnType(); const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault(); if (LCD == LCD_None) LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_None; else if (LCD == LCD_ByCopy) LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByval; else if (LCD == LCD_ByRef) LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByref; DeclarationNameInfo DNI = CallOperator->getNameInfo(); LSI->IntroducerRange = DNI.getCXXOperatorNameRange(); LSI->Mutable = !CallOperator->isConst(); // Add the captures to the LSI so they can be noted as already // captured within tryCaptureVar. auto I = LambdaClass->field_begin(); for (const auto &C : LambdaClass->captures()) { if (C.capturesVariable()) { VarDecl *VD = C.getCapturedVar(); if (VD->isInitCapture()) S.CurrentInstantiationScope->InstantiatedLocal(VD, VD); QualType CaptureType = VD->getType(); const bool ByRef = C.getCaptureKind() == LCK_ByRef; LSI->addCapture(VD, /*IsBlock*/false, ByRef, /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(), /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), CaptureType, /*Expr*/ nullptr); } else if (C.capturesThis()) { LSI->addThisCapture(/*Nested*/ false, C.getLocation(), /*Expr*/ nullptr, C.getCaptureKind() == LCK_StarThis); } else { LSI->addVLATypeCapture(C.getLocation(), I->getType()); } ++I; } } Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, SkipBodyInfo *SkipBody) { if (!D) return D; FunctionDecl *FD = nullptr; if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) FD = FunTmpl->getTemplatedDecl(); else FD = cast(D); // Check for defining attributes before the check for redefinition. if (const auto *Attr = FD->getAttr()) { Diag(Attr->getLocation(), diag::err_alias_is_definition) << FD << 0; FD->dropAttr(); FD->setInvalidDecl(); } if (const auto *Attr = FD->getAttr()) { Diag(Attr->getLocation(), diag::err_alias_is_definition) << FD << 1; FD->dropAttr(); FD->setInvalidDecl(); } // See if this is a redefinition. if (!FD->isLateTemplateParsed()) { CheckForFunctionRedefinition(FD, nullptr, SkipBody); // If we're skipping the body, we're done. Don't enter the scope. if (SkipBody && SkipBody->ShouldSkip) return D; } // Mark this function as "will have a body eventually". This lets users to // call e.g. isInlineDefinitionExternallyVisible while we're still parsing // this function. FD->setWillHaveBody(); // If we are instantiating a generic lambda call operator, push // a LambdaScopeInfo onto the function stack. But use the information // that's already been calculated (ActOnLambdaExpr) to prime the current // LambdaScopeInfo. // When the template operator is being specialized, the LambdaScopeInfo, // has to be properly restored so that tryCaptureVariable doesn't try // and capture any new variables. In addition when calculating potential // captures during transformation of nested lambdas, it is necessary to // have the LSI properly restored. if (isGenericLambdaCallOperatorSpecialization(FD)) { assert(inTemplateInstantiation() && "There should be an active template instantiation on the stack " "when instantiating a generic lambda!"); RebuildLambdaScopeInfo(cast(D), *this); } else { // Enter a new function scope PushFunctionScope(); } // Builtin functions cannot be defined. if (unsigned BuiltinID = FD->getBuiltinID()) { if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID) && !Context.BuiltinInfo.isPredefinedRuntimeFunction(BuiltinID)) { Diag(FD->getLocation(), diag::err_builtin_definition) << FD; FD->setInvalidDecl(); } } // The return type of a function definition must be complete // (C99 6.9.1p3, C++ [dcl.fct]p6). QualType ResultType = FD->getReturnType(); if (!ResultType->isDependentType() && !ResultType->isVoidType() && !FD->isInvalidDecl() && RequireCompleteType(FD->getLocation(), ResultType, diag::err_func_def_incomplete_result)) FD->setInvalidDecl(); if (FnBodyScope) PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters CheckParmsForFunctionDef(FD->parameters(), /*CheckParameterNames=*/true); // Add non-parameter declarations already in the function to the current // scope. if (FnBodyScope) { for (Decl *NPD : FD->decls()) { auto *NonParmDecl = dyn_cast(NPD); if (!NonParmDecl) continue; assert(!isa(NonParmDecl) && "parameters should not be in newly created FD yet"); // If the decl has a name, make it accessible in the current scope. if (NonParmDecl->getDeclName()) PushOnScopeChains(NonParmDecl, FnBodyScope, /*AddToContext=*/false); // Similarly, dive into enums and fish their constants out, making them // accessible in this scope. if (auto *ED = dyn_cast(NonParmDecl)) { for (auto *EI : ED->enumerators()) PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false); } } } // Introduce our parameters into the function scope for (auto Param : FD->parameters()) { Param->setOwningFunction(FD); // If this has an identifier, add it to the scope stack. if (Param->getIdentifier() && FnBodyScope) { CheckShadow(FnBodyScope, Param); PushOnScopeChains(Param, FnBodyScope); } } // Ensure that the function's exception specification is instantiated. if (const FunctionProtoType *FPT = FD->getType()->getAs()) ResolveExceptionSpec(D->getLocation(), FPT); // dllimport cannot be applied to non-inline function definitions. if (FD->hasAttr() && !FD->isInlined() && !FD->isTemplateInstantiation()) { assert(!FD->hasAttr()); Diag(FD->getLocation(), diag::err_attribute_dllimport_function_definition); FD->setInvalidDecl(); return D; } // We want to attach documentation to original Decl (which might be // a function template). ActOnDocumentableDecl(D); if (getCurLexicalContext()->isObjCContainer() && getCurLexicalContext()->getDeclKind() != Decl::ObjCCategoryImpl && getCurLexicalContext()->getDeclKind() != Decl::ObjCImplementation) Diag(FD->getLocation(), diag::warn_function_def_in_objc_container); return D; } /// \brief Given the set of return statements within a function body, /// compute the variables that are subject to the named return value /// optimization. /// /// Each of the variables that is subject to the named return value /// optimization will be marked as NRVO variables in the AST, and any /// return statement that has a marked NRVO variable as its NRVO candidate can /// use the named return value optimization. /// /// This function applies a very simplistic algorithm for NRVO: if every return /// statement in the scope of a variable has the same NRVO candidate, that /// candidate is an NRVO variable. void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { ReturnStmt **Returns = Scope->Returns.data(); for (unsigned I = 0, E = Scope->Returns.size(); I != E; ++I) { if (const VarDecl *NRVOCandidate = Returns[I]->getNRVOCandidate()) { if (!NRVOCandidate->isNRVOVariable()) Returns[I]->setNRVOCandidate(nullptr); } } } bool Sema::canDelayFunctionBody(const Declarator &D) { // We can't delay parsing the body of a constexpr function template (yet). if (D.getDeclSpec().isConstexprSpecified()) return false; // We can't delay parsing the body of a function template with a deduced // return type (yet). if (D.getDeclSpec().hasAutoTypeSpec()) { // If the placeholder introduces a non-deduced trailing return type, // we can still delay parsing it. if (D.getNumTypeObjects()) { const auto &Outer = D.getTypeObject(D.getNumTypeObjects() - 1); if (Outer.Kind == DeclaratorChunk::Function && Outer.Fun.hasTrailingReturnType()) { QualType Ty = GetTypeFromParser(Outer.Fun.getTrailingReturnType()); return Ty.isNull() || !Ty->isUndeducedType(); } } return false; } return true; } bool Sema::canSkipFunctionBody(Decl *D) { // We cannot skip the body of a function (or function template) which is // constexpr, since we may need to evaluate its body in order to parse the // rest of the file. // We cannot skip the body of a function with an undeduced return type, // because any callers of that function need to know the type. if (const FunctionDecl *FD = D->getAsFunction()) if (FD->isConstexpr() || FD->getReturnType()->isUndeducedType()) return false; return Consumer.shouldSkipFunctionBody(D); } Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) { if (FunctionDecl *FD = dyn_cast_or_null(Decl)) FD->setHasSkippedBody(); else if (ObjCMethodDecl *MD = dyn_cast_or_null(Decl)) MD->setHasSkippedBody(); return Decl; } Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { return ActOnFinishFunctionBody(D, BodyArg, false); } Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation) { FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr; sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; if (getLangOpts().CoroutinesTS && getCurFunction()->CoroutinePromise) CheckCompletedCoroutineBody(FD, Body); if (FD) { FD->setBody(Body); if (getLangOpts().CPlusPlus14) { if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) { // If the function has a deduced result type but contains no 'return' // statements, the result type as written must be exactly 'auto', and // the deduced result type is 'void'. if (!FD->getReturnType()->getAs()) { Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) << FD->getReturnType(); FD->setInvalidDecl(); } else { // Substitute 'void' for the 'auto' in the type. TypeLoc ResultType = getReturnTypeLoc(FD); Context.adjustDeducedFunctionResultType( FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); } } } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { // In C++11, we don't use 'auto' deduction rules for lambda call // operators because we don't support return type deduction. auto *LSI = getCurLambda(); if (LSI->HasImplicitReturnType) { deduceClosureReturnType(*LSI); // C++11 [expr.prim.lambda]p4: // [...] if there are no return statements in the compound-statement // [the deduced type is] the type void QualType RetType = LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType; // Update the return type to the deduced type. const FunctionProtoType *Proto = FD->getType()->getAs(); FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(), Proto->getExtProtoInfo())); } } // The only way to be included in UndefinedButUsed is if there is an // ODR use before the definition. Avoid the expensive map lookup if this // is the first declaration. if (!FD->isFirstDecl() && FD->getPreviousDecl()->isUsed()) { if (!FD->isExternallyVisible()) UndefinedButUsed.erase(FD); else if (FD->isInlined() && !LangOpts.GNUInline && (!FD->getPreviousDecl()->hasAttr())) UndefinedButUsed.erase(FD); } // If the function implicitly returns zero (like 'main') or is naked, // don't complain about missing return statements. if (FD->hasImplicitReturnZero() || FD->hasAttr()) WP.disableCheckFallThrough(); // MSVC permits the use of pure specifier (=0) on function definition, // defined at class scope, warn about this non-standard construct. if (getLangOpts().MicrosoftExt && FD->isPure() && FD->isCanonicalDecl()) Diag(FD->getLocation(), diag::ext_pure_function_definition); if (!FD->isInvalidDecl()) { // Don't diagnose unused parameters of defaulted or deleted functions. if (!FD->isDeleted() && !FD->isDefaulted()) DiagnoseUnusedParameters(FD->parameters()); DiagnoseSizeOfParametersAndReturnValue(FD->parameters(), FD->getReturnType(), FD); // If this is a structor, we need a vtable. if (CXXConstructorDecl *Constructor = dyn_cast(FD)) MarkVTableUsed(FD->getLocation(), Constructor->getParent()); else if (CXXDestructorDecl *Destructor = dyn_cast(FD)) MarkVTableUsed(FD->getLocation(), Destructor->getParent()); // Try to apply the named return value optimization. We have to check // if we can do this here because lambdas keep return statements around // to deduce an implicit return type. if (getLangOpts().CPlusPlus && FD->getReturnType()->isRecordType() && !FD->isDependentContext()) computeNRVO(Body, getCurFunction()); } // GNU warning -Wmissing-prototypes: // Warn if a global function is defined without a previous // prototype declaration. This warning is issued even if the // definition itself provides a prototype. The aim is to detect // global functions that fail to be declared in header files. const FunctionDecl *PossibleZeroParamPrototype = nullptr; if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) { Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; if (PossibleZeroParamPrototype) { // We found a declaration that is not a prototype, // but that could be a zero-parameter prototype if (TypeSourceInfo *TI = PossibleZeroParamPrototype->getTypeSourceInfo()) { TypeLoc TL = TI->getTypeLoc(); if (FunctionNoProtoTypeLoc FTL = TL.getAs()) Diag(PossibleZeroParamPrototype->getLocation(), diag::note_declaration_not_a_prototype) << PossibleZeroParamPrototype << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void"); } } // GNU warning -Wstrict-prototypes // Warn if K&R function is defined without a previous declaration. // This warning is issued only if the definition itself does not provide // a prototype. Only K&R definitions do not provide a prototype. // An empty list in a function declarator that is part of a definition // of that function specifies that the function has no parameters // (C99 6.7.5.3p14) if (!FD->hasWrittenPrototype() && FD->getNumParams() > 0 && !LangOpts.CPlusPlus) { TypeSourceInfo *TI = FD->getTypeSourceInfo(); TypeLoc TL = TI->getTypeLoc(); FunctionTypeLoc FTL = TL.getAsAdjusted(); Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 1; } } if (auto *MD = dyn_cast(FD)) { const CXXMethodDecl *KeyFunction; if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) && MD->isVirtual() && (KeyFunction = Context.getCurrentKeyFunction(MD->getParent())) && MD == KeyFunction->getCanonicalDecl()) { // Update the key-function state if necessary for this ABI. if (FD->isInlined() && !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { Context.setNonKeyFunction(MD); // If the newly-chosen key function is already defined, then we // need to mark the vtable as used retroactively. KeyFunction = Context.getCurrentKeyFunction(MD->getParent()); const FunctionDecl *Definition; if (KeyFunction && KeyFunction->isDefined(Definition)) MarkVTableUsed(Definition->getLocation(), MD->getParent(), true); } else { // We just defined they key function; mark the vtable as used. MarkVTableUsed(FD->getLocation(), MD->getParent(), true); } } } assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); if (!MD->isInvalidDecl()) { DiagnoseUnusedParameters(MD->parameters()); DiagnoseSizeOfParametersAndReturnValue(MD->parameters(), MD->getReturnType(), MD); if (Body) computeNRVO(Body, getCurFunction()); } if (getCurFunction()->ObjCShouldCallSuper) { Diag(MD->getLocEnd(), diag::warn_objc_missing_super_call) << MD->getSelector().getAsString(); getCurFunction()->ObjCShouldCallSuper = false; } if (getCurFunction()->ObjCWarnForNoDesignatedInitChain) { const ObjCMethodDecl *InitMethod = nullptr; bool isDesignated = MD->isDesignatedInitializerForTheInterface(&InitMethod); assert(isDesignated && InitMethod); (void)isDesignated; auto superIsNSObject = [&](const ObjCMethodDecl *MD) { auto IFace = MD->getClassInterface(); if (!IFace) return false; auto SuperD = IFace->getSuperClass(); if (!SuperD) return false; return SuperD->getIdentifier() == NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); }; // Don't issue this warning for unavailable inits or direct subclasses // of NSObject. if (!MD->isUnavailable() && !superIsNSObject(MD)) { Diag(MD->getLocation(), diag::warn_objc_designated_init_missing_super_call); Diag(InitMethod->getLocation(), diag::note_objc_designated_init_marked_here); } getCurFunction()->ObjCWarnForNoDesignatedInitChain = false; } if (getCurFunction()->ObjCWarnForNoInitDelegation) { // Don't issue this warning for unavaialable inits. if (!MD->isUnavailable()) Diag(MD->getLocation(), diag::warn_objc_secondary_init_missing_init_call); getCurFunction()->ObjCWarnForNoInitDelegation = false; } } else { return nullptr; } if (Body && getCurFunction()->HasPotentialAvailabilityViolations) DiagnoseUnguardedAvailabilityViolations(dcl); assert(!getCurFunction()->ObjCShouldCallSuper && "This should only be set for ObjC methods, which should have been " "handled in the block above."); // Verify and clean out per-function state. if (Body && (!FD || !FD->isDefaulted())) { // C++ constructors that have function-try-blocks can't have return // statements in the handlers of that block. (C++ [except.handle]p14) // Verify this. if (FD && isa(FD) && isa(Body)) DiagnoseReturnInConstructorExceptionHandler(cast(Body)); // Verify that gotos and switch cases don't jump into scopes illegally. if (getCurFunction()->NeedsScopeChecking() && !PP.isCodeCompletionEnabled()) DiagnoseInvalidJumps(Body); if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) { if (!Destructor->getParent()->isDependentType()) CheckDestructor(Destructor); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); } // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. if (getDiagnostics().hasErrorOccurred() || getDiagnostics().getSuppressAllDiagnostics()) { DiscardCleanupsInEvaluationContext(); } if (!getDiagnostics().hasUncompilableErrorOccurred() && !isa(dcl)) { // Since the body is valid, issue any analysis-based warnings that are // enabled. ActivePolicy = &WP; } if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() && (!CheckConstexprFunctionDecl(FD) || !CheckConstexprFunctionBody(FD, Body))) FD->setInvalidDecl(); if (FD && FD->hasAttr()) { for (const Stmt *S : Body->children()) { // Allow local register variables without initializer as they don't // require prologue. bool RegisterVariables = false; if (auto *DS = dyn_cast(S)) { for (const auto *Decl : DS->decls()) { if (const auto *Var = dyn_cast(Decl)) { RegisterVariables = Var->hasAttr() && !Var->hasInit(); if (!RegisterVariables) break; } } } if (RegisterVariables) continue; if (!isa(S) && !isa(S)) { Diag(S->getLocStart(), diag::err_non_asm_stmt_in_naked_function); Diag(FD->getAttr()->getLocation(), diag::note_attribute); FD->setInvalidDecl(); break; } } } assert(ExprCleanupObjects.size() == ExprEvalContexts.back().NumCleanupObjects && "Leftover temporaries in function"); assert(!Cleanup.exprNeedsCleanups() && "Unaccounted cleanups in function"); assert(MaybeODRUseExprs.empty() && "Leftover expressions for odr-use checking"); } if (!IsInstantiation) PopDeclContext(); PopFunctionScopeInfo(ActivePolicy, dcl); // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. if (getDiagnostics().hasErrorOccurred()) { DiscardCleanupsInEvaluationContext(); } return dcl; } /// When we finish delayed parsing of an attribute, we must attach it to the /// relevant Decl. void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs) { // Always attach attributes to the underlying decl. if (TemplateDecl *TD = dyn_cast(D)) D = TD->getTemplatedDecl(); ProcessDeclAttributeList(S, D, Attrs.getList()); if (CXXMethodDecl *Method = dyn_cast_or_null(D)) if (Method->isStatic()) checkThisInStaticMemberFunctionAttributes(Method); } /// ImplicitlyDefineFunction - An undeclared identifier was used in a function /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S) { // Before we produce a declaration for an implicitly defined // function, see whether there was a locally-scoped declaration of // this name as a function or variable. If so, use that // (non-visible) declaration, and complain about it. if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) { Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev; Diag(ExternCPrev->getLocation(), diag::note_previous_declaration); return ExternCPrev; } // Extension in C99. Legal in C90, but warn about it. unsigned diag_id; if (II.getName().startswith("__builtin_")) diag_id = diag::warn_builtin_unknown; else if (getLangOpts().C99) diag_id = diag::ext_implicit_function_decl; else diag_id = diag::warn_implicit_function_decl; Diag(Loc, diag_id) << &II; // Because typo correction is expensive, only do it if the implicit // function declaration is going to be treated as an error. if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) { TypoCorrection Corrected; if (S && (Corrected = CorrectTypo( DeclarationNameInfo(&II, Loc), LookupOrdinaryName, S, nullptr, llvm::make_unique>(), CTK_NonError))) diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion), /*ErrorRecovery*/false); } // Set a Declarator for the implicit definition: int foo(); const char *Dummy; AttributeFactory attrFactory; DeclSpec DS(attrFactory); unsigned DiagID; bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID, Context.getPrintingPolicy()); (void)Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); SourceLocation NoLoc; Declarator D(DS, Declarator::BlockContext); D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false, /*IsAmbiguous=*/false, /*LParenLoc=*/NoLoc, /*Params=*/nullptr, /*NumParams=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, /*TypeQuals=*/0, /*RefQualifierIsLvalueRef=*/true, /*RefQualifierLoc=*/NoLoc, /*ConstQualifierLoc=*/NoLoc, /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, /*DeclsInPrototype=*/None, Loc, Loc, D), DS.getAttributes(), SourceLocation()); D.SetIdentifier(&II, Loc); // Insert this function into translation-unit scope. DeclContext *PrevDC = CurContext; CurContext = Context.getTranslationUnitDecl(); FunctionDecl *FD = cast(ActOnDeclarator(TUScope, D)); FD->setImplicit(); CurContext = PrevDC; AddKnownFunctionAttributes(FD); return FD; } /// \brief Adds any function attributes that we know a priori based on /// the declaration of this function. /// /// These attributes can apply both to implicitly-declared builtins /// (like __builtin___printf_chk) or to library-declared functions /// like NSLog or printf. /// /// We need to check for duplicate attributes both here and where user-written /// attributes are applied to declarations. void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { if (FD->isInvalidDecl()) return; // If this is a built-in function, map its builtin attributes to // actual attributes. if (unsigned BuiltinID = FD->getBuiltinID()) { // Handle printf-formatting attributes. unsigned FormatIdx; bool HasVAListArg; if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) { if (!FD->hasAttr()) { const char *fmt = "printf"; unsigned int NumParams = FD->getNumParams(); if (FormatIdx < NumParams && // NumParams may be 0 (e.g. vfprintf) FD->getParamDecl(FormatIdx)->getType()->isObjCObjectPointerType()) fmt = "NSString"; FD->addAttr(FormatAttr::CreateImplicit(Context, &Context.Idents.get(fmt), FormatIdx+1, HasVAListArg ? 0 : FormatIdx+2, FD->getLocation())); } } if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx, HasVAListArg)) { if (!FD->hasAttr()) FD->addAttr(FormatAttr::CreateImplicit(Context, &Context.Idents.get("scanf"), FormatIdx+1, HasVAListArg ? 0 : FormatIdx+2, FD->getLocation())); } // Mark const if we don't care about errno and that is the only // thing preventing the function from being const. This allows // IRgen to use LLVM intrinsics for such functions. if (!getLangOpts().MathErrno && Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) { if (!FD->hasAttr()) FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); } if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && !FD->hasAttr()) FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context, FD->getLocation())); if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->hasAttr()) FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation())); if (Context.BuiltinInfo.isPure(BuiltinID) && !FD->hasAttr()) FD->addAttr(PureAttr::CreateImplicit(Context, FD->getLocation())); if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->hasAttr()) FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); if (getLangOpts().CUDA && Context.BuiltinInfo.isTSBuiltin(BuiltinID) && !FD->hasAttr() && !FD->hasAttr()) { // Add the appropriate attribute, depending on the CUDA compilation mode // and which target the builtin belongs to. For example, during host // compilation, aux builtins are __device__, while the rest are __host__. if (getLangOpts().CUDAIsDevice != Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) FD->addAttr(CUDADeviceAttr::CreateImplicit(Context, FD->getLocation())); else FD->addAttr(CUDAHostAttr::CreateImplicit(Context, FD->getLocation())); } } // If C++ exceptions are enabled but we are told extern "C" functions cannot // throw, add an implicit nothrow attribute to any extern "C" function we come // across. if (getLangOpts().CXXExceptions && getLangOpts().ExternCNoUnwind && FD->isExternC() && !FD->hasAttr()) { const auto *FPT = FD->getType()->getAs(); if (!FPT || FPT->getExceptionSpecType() == EST_None) FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation())); } IdentifierInfo *Name = FD->getIdentifier(); if (!Name) return; if ((!getLangOpts().CPlusPlus && FD->getDeclContext()->isTranslationUnit()) || (isa(FD->getDeclContext()) && cast(FD->getDeclContext())->getLanguage() == LinkageSpecDecl::lang_c)) { // Okay: this could be a libc/libm/Objective-C function we know // about. } else return; if (Name->isStr("asprintf") || Name->isStr("vasprintf")) { // FIXME: asprintf and vasprintf aren't C99 functions. Should they be // target-specific builtins, perhaps? if (!FD->hasAttr()) FD->addAttr(FormatAttr::CreateImplicit(Context, &Context.Idents.get("printf"), 2, Name->isStr("vasprintf") ? 0 : 3, FD->getLocation())); } if (Name->isStr("__CFStringMakeConstantString")) { // We already have a __builtin___CFStringMakeConstantString, // but builds that use -fno-constant-cfstrings don't go through that. if (!FD->hasAttr()) FD->addAttr(FormatArgAttr::CreateImplicit(Context, 1, FD->getLocation())); } } TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo) { assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); if (!TInfo) { assert(D.isInvalidType() && "no declarator info for valid type"); TInfo = Context.getTrivialTypeSourceInfo(T); } // Scope manipulation handled by caller. TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, D.getLocStart(), D.getIdentifierLoc(), D.getIdentifier(), TInfo); // Bail out immediately if we have an invalid declaration. if (D.isInvalidType()) { NewTD->setInvalidDecl(); return NewTD; } if (D.getDeclSpec().isModulePrivateSpecified()) { if (CurContext->isFunctionOrMethod()) Diag(NewTD->getLocation(), diag::err_module_private_local) << 2 << NewTD->getDeclName() << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); else NewTD->setModulePrivate(); } // C++ [dcl.typedef]p8: // 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. // We need to check whether the type was declared in the declaration. switch (D.getDeclSpec().getTypeSpecType()) { case TST_enum: case TST_struct: case TST_interface: case TST_union: case TST_class: { TagDecl *tagFromDeclSpec = cast(D.getDeclSpec().getRepAsDecl()); setTagNameForLinkagePurposes(tagFromDeclSpec, NewTD); break; } default: break; } return NewTD; } /// \brief Check that this is a valid underlying type for an enum declaration. bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); QualType T = TI->getType(); if (T->isDependentType()) return false; if (const BuiltinType *BT = T->getAs()) if (BT->isInteger()) return false; Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T; return true; } /// Check whether this is a valid redeclaration of a previous enumeration. /// \return true if the redeclaration was invalid. bool Sema::CheckEnumRedeclaration( SourceLocation EnumLoc, bool IsScoped, QualType EnumUnderlyingTy, bool EnumUnderlyingIsImplicit, const EnumDecl *Prev) { bool IsFixed = !EnumUnderlyingTy.isNull(); if (IsScoped != Prev->isScoped()) { Diag(EnumLoc, diag::err_enum_redeclare_scoped_mismatch) << Prev->isScoped(); Diag(Prev->getLocation(), diag::note_previous_declaration); return true; } if (IsFixed && Prev->isFixed()) { if (!EnumUnderlyingTy->isDependentType() && !Prev->getIntegerType()->isDependentType() && !Context.hasSameUnqualifiedType(EnumUnderlyingTy, Prev->getIntegerType())) { // TODO: Highlight the underlying type of the redeclaration. Diag(EnumLoc, diag::err_enum_redeclare_type_mismatch) << EnumUnderlyingTy << Prev->getIntegerType(); Diag(Prev->getLocation(), diag::note_previous_declaration) << Prev->getIntegerTypeRange(); return true; } } else if (IsFixed && !Prev->isFixed() && EnumUnderlyingIsImplicit) { ; } else if (!IsFixed && Prev->isFixed() && !Prev->getIntegerTypeSourceInfo()) { ; } else if (IsFixed != Prev->isFixed()) { Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch) << Prev->isFixed(); Diag(Prev->getLocation(), diag::note_previous_declaration); return true; } return false; } /// \brief Get diagnostic %select index for tag kind for /// redeclaration diagnostic message. /// WARNING: Indexes apply to particular diagnostics only! /// /// \returns diagnostic %select index. static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag) { switch (Tag) { case TTK_Struct: return 0; case TTK_Interface: return 1; case TTK_Class: return 2; default: llvm_unreachable("Invalid tag kind for redecl diagnostic!"); } } /// \brief Determine if tag kind is a class-key compatible with /// class for redeclaration (class, struct, or __interface). /// /// \returns true iff the tag kind is compatible. static bool isClassCompatTagKind(TagTypeKind Tag) { return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface; } Sema::NonTagKind Sema::getNonTagTypeDeclKind(const Decl *PrevDecl, TagTypeKind TTK) { if (isa(PrevDecl)) return NTK_Typedef; else if (isa(PrevDecl)) return NTK_TypeAlias; else if (isa(PrevDecl)) return NTK_Template; else if (isa(PrevDecl)) return NTK_TypeAliasTemplate; else if (isa(PrevDecl)) return NTK_TemplateTemplateArgument; switch (TTK) { case TTK_Struct: case TTK_Interface: case TTK_Class: return getLangOpts().CPlusPlus ? NTK_NonClass : NTK_NonStruct; case TTK_Union: return NTK_NonUnion; case TTK_Enum: return NTK_NonEnum; } llvm_unreachable("invalid TTK"); } /// \brief Determine whether a tag with a given kind is acceptable /// as a redeclaration of the given tag declaration. /// /// \returns true if the new tag kind is acceptable, false otherwise. bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo *Name) { // C++ [dcl.type.elab]p3: // The class-key or enum keyword present in the // elaborated-type-specifier shall agree in kind with the // declaration to which the name in the elaborated-type-specifier // refers. This rule also applies to the form of // elaborated-type-specifier that declares a class-name or // friend class since it can be construed as referring to the // definition of the class. Thus, in any // elaborated-type-specifier, the enum keyword shall be used to // refer to an enumeration (7.2), the union class-key shall be // used to refer to a union (clause 9), and either the class or // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. TagTypeKind OldTag = Previous->getTagKind(); if (!isDefinition || !isClassCompatTagKind(NewTag)) if (OldTag == NewTag) return true; if (isClassCompatTagKind(OldTag) && isClassCompatTagKind(NewTag)) { // Warn about the struct/class tag mismatch. bool isTemplate = false; if (const CXXRecordDecl *Record = dyn_cast(Previous)) isTemplate = Record->getDescribedClassTemplate(); if (inTemplateInstantiation()) { // In a template instantiation, do not offer fix-its for tag mismatches // since they usually mess up the template instead of fixing the problem. Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(OldTag); return true; } if (isDefinition) { // On definitions, check previous tags and issue a fix-it for each // one that doesn't match the current tag. if (Previous->getDefinition()) { // Don't suggest fix-its for redefinitions. return true; } bool previousMismatch = false; for (auto I : Previous->redecls()) { if (I->getTagKind() != NewTag) { if (!previousMismatch) { previousMismatch = true; Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(I->getTagKind()); } Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) << getRedeclDiagFromTagKind(NewTag) << FixItHint::CreateReplacement(I->getInnerLocStart(), TypeWithKeyword::getTagTypeKindName(NewTag)); } } return true; } // Check for a previous definition. If current tag and definition // are same type, do nothing. If no definition, but disagree with // with previous tag type, give a warning, but no fix-it. const TagDecl *Redecl = Previous->getDefinition() ? Previous->getDefinition() : Previous; if (Redecl->getTagKind() == NewTag) { return true; } Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << getRedeclDiagFromTagKind(NewTag) << isTemplate << Name << getRedeclDiagFromTagKind(OldTag); Diag(Redecl->getLocation(), diag::note_previous_use); // If there is a previous definition, suggest a fix-it. if (Previous->getDefinition()) { Diag(NewTagLoc, diag::note_struct_class_suggestion) << getRedeclDiagFromTagKind(Redecl->getTagKind()) << FixItHint::CreateReplacement(SourceRange(NewTagLoc), TypeWithKeyword::getTagTypeKindName(Redecl->getTagKind())); } return true; } return false; } /// Add a minimal nested name specifier fixit hint to allow lookup of a tag name /// from an outer enclosing namespace or file scope inside a friend declaration. /// This should provide the commented out code in the following snippet: /// namespace N { /// struct X; /// namespace M { /// struct Y { friend struct /*N::*/ X; }; /// } /// } static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S, SourceLocation NameLoc) { // While the decl is in a namespace, do repeated lookup of that name and see // if we get the same namespace back. If we do not, continue until // translation unit scope, at which point we have a fully qualified NNS. SmallVector Namespaces; DeclContext *DC = ND->getDeclContext()->getRedeclContext(); for (; !DC->isTranslationUnit(); DC = DC->getParent()) { // This tag should be declared in a namespace, which can only be enclosed by // other namespaces. Bail if there's an anonymous namespace in the chain. NamespaceDecl *Namespace = dyn_cast(DC); if (!Namespace || Namespace->isAnonymousNamespace()) return FixItHint(); IdentifierInfo *II = Namespace->getIdentifier(); Namespaces.push_back(II); NamedDecl *Lookup = SemaRef.LookupSingleName( S, II, NameLoc, Sema::LookupNestedNameSpecifierName); if (Lookup == Namespace) break; } // Once we have all the namespaces, reverse them to go outermost first, and // build an NNS. SmallString<64> Insertion; llvm::raw_svector_ostream OS(Insertion); if (DC->isTranslationUnit()) OS << "::"; std::reverse(Namespaces.begin(), Namespaces.end()); for (auto *II : Namespaces) OS << II->getName() << "::"; return FixItHint::CreateInsertion(NameLoc, Insertion); } /// \brief Determine whether a tag originally declared in context \p OldDC can /// be redeclared with an unqualfied name in \p NewDC (assuming name lookup /// found a declaration in \p OldDC as a previous decl, perhaps through a /// using-declaration). static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC, DeclContext *NewDC) { OldDC = OldDC->getRedeclContext(); NewDC = NewDC->getRedeclContext(); if (OldDC->Equals(NewDC)) return true; // In MSVC mode, we allow a redeclaration if the contexts are related (either // encloses the other). if (S.getLangOpts().MSVCCompat && (OldDC->Encloses(NewDC) || NewDC->Encloses(OldDC))) return true; return false; } /// \brief This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. /// /// \param IsTypeSpecifier \c true if this is a type-specifier (or /// trailing-type-specifier) other than one in an alias-declaration. /// /// \param SkipBody If non-null, will be set to indicate if the caller should /// skip the definition of this tag and treat it as if it were a declaration. Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, SkipBodyInfo *SkipBody) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != nullptr || TUK == TUK_Definition) && "Nameless record must be a definition!"); assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference); OwnedDecl = false; TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); bool ScopedEnum = ScopedEnumKWLoc.isValid(); // FIXME: Check member specializations more carefully. bool isMemberSpecialization = false; bool Invalid = false; // We only need to do this matching if we have template parameters // or a scope specifier, which also conveniently avoids this work // for non-C++ cases. if (TemplateParameterLists.size() > 0 || (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( KWLoc, NameLoc, SS, nullptr, TemplateParameterLists, TUK == TUK_Friend, isMemberSpecialization, Invalid)) { if (Kind == TTK_Enum) { Diag(KWLoc, diag::err_enum_template); return nullptr; } if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may // be a member of another template). if (Invalid) return nullptr; OwnedDecl = false; DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attr, TemplateParams, AS, ModulePrivateLoc, /*FriendLoc*/SourceLocation(), TemplateParameterLists.size()-1, TemplateParameterLists.data(), SkipBody); return Result.get(); } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) << TypeWithKeyword::getTagTypeKindName(Kind) << Name; isMemberSpecialization = true; } } } // Figure out the underlying type if this a enum declaration. We need to do // this early, because it's needed to detect if this is an incompatible // redeclaration. llvm::PointerUnion EnumUnderlying; bool EnumUnderlyingIsImplicit = false; if (Kind == TTK_Enum) { if (UnderlyingType.isInvalid() || (!UnderlyingType.get() && ScopedEnum)) // No underlying type explicitly specified, or we failed to parse the // type, default to int. EnumUnderlying = Context.IntTy.getTypePtr(); else if (UnderlyingType.get()) { // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an // integral type; any cv-qualification is ignored. TypeSourceInfo *TI = nullptr; GetTypeFromParser(UnderlyingType.get(), &TI); EnumUnderlying = TI; if (CheckEnumUnderlyingType(TI)) // Recover by falling back to int. EnumUnderlying = Context.IntTy.getTypePtr(); if (DiagnoseUnexpandedParameterPack(TI->getTypeLoc().getBeginLoc(), TI, UPPC_FixedUnderlyingType)) EnumUnderlying = Context.IntTy.getTypePtr(); } else if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { if (getLangOpts().MSVCCompat || TUK == TUK_Definition) { // Microsoft enums are always of int type. EnumUnderlying = Context.IntTy.getTypePtr(); EnumUnderlyingIsImplicit = true; } } } DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; bool isStdBadAlloc = false; bool isStdAlignValT = false; RedeclarationKind Redecl = ForRedeclaration; if (TUK == TUK_Friend || TUK == TUK_Reference) Redecl = NotForRedeclaration; LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl); if (Name && SS.isNotEmpty()) { // We have a nested-name tag ('struct foo::bar'). // Check for invalid 'foo::'. if (SS.isInvalid()) { Name = nullptr; goto CreateNewDecl; } // If this is a friend or a reference to a class in a dependent // context, don't try to make a decl for it. if (TUK == TUK_Friend || TUK == TUK_Reference) { DC = computeDeclContext(SS, false); if (!DC) { IsDependent = true; return nullptr; } } else { DC = computeDeclContext(SS, true); if (!DC) { Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec) << SS.getRange(); return nullptr; } } if (RequireCompleteDeclContext(SS, DC)) return nullptr; SearchDC = DC; // Look-up name inside 'foo::'. LookupQualifiedName(Previous, DC); if (Previous.isAmbiguous()) return nullptr; if (Previous.empty()) { // Name lookup did not find anything. However, if the // nested-name-specifier refers to the current instantiation, // and that current instantiation has any dependent base // classes, we might find something at instantiation time: treat // this as a dependent elaborated-type-specifier. // But this only makes any sense for reference-like lookups. if (Previous.wasNotFoundInCurrentInstantiation() && (TUK == TUK_Reference || TUK == TUK_Friend)) { IsDependent = true; return nullptr; } // A tag 'foo::bar' must already exist. Diag(NameLoc, diag::err_not_tag_in_scope) << Kind << Name << DC << SS.getRange(); Name = nullptr; Invalid = true; goto CreateNewDecl; } } else if (Name) { // C++14 [class.mem]p14: // If T is the name of a class, then each of the following shall have a // name different from T: // -- every member of class T that is itself a type if (TUK != TUK_Reference && TUK != TUK_Friend && DiagnoseClassNameShadow(SearchDC, DeclarationNameInfo(Name, NameLoc))) return nullptr; // If this is a named struct, check to see if there was a previous forward // declaration or definition. // FIXME: We're looking into outer scopes here, even when we // shouldn't be. Doing so can result in ambiguities that we // shouldn't be diagnosing. LookupName(Previous, S); // When declaring or defining a tag, ignore ambiguities introduced // by types using'ed into this scope. if (Previous.isAmbiguous() && (TUK == TUK_Definition || TUK == TUK_Declaration)) { LookupResult::Filter F = Previous.makeFilter(); while (F.hasNext()) { NamedDecl *ND = F.next(); if (!ND->getDeclContext()->getRedeclContext()->Equals( SearchDC->getRedeclContext())) F.erase(); } F.done(); } // C++11 [namespace.memdef]p3: // If the name in a friend declaration is neither qualified nor // a template-id and the declaration is a function or an // elaborated-type-specifier, the lookup to determine whether // the entity has been previously declared shall not consider // any scopes outside the innermost enclosing namespace. // // MSVC doesn't implement the above rule for types, so a friend tag // declaration may be a redeclaration of a type declared in an enclosing // scope. They do implement this rule for friend functions. // // Does it matter that this should be by scope instead of by // semantic context? if (!Previous.empty() && TUK == TUK_Friend) { DeclContext *EnclosingNS = SearchDC->getEnclosingNamespaceContext(); LookupResult::Filter F = Previous.makeFilter(); bool FriendSawTagOutsideEnclosingNamespace = false; while (F.hasNext()) { NamedDecl *ND = F.next(); DeclContext *DC = ND->getDeclContext()->getRedeclContext(); if (DC->isFileContext() && !EnclosingNS->Encloses(ND->getDeclContext())) { if (getLangOpts().MSVCCompat) FriendSawTagOutsideEnclosingNamespace = true; else F.erase(); } } F.done(); // Diagnose this MSVC extension in the easy case where lookup would have // unambiguously found something outside the enclosing namespace. if (Previous.isSingleResult() && FriendSawTagOutsideEnclosingNamespace) { NamedDecl *ND = Previous.getFoundDecl(); Diag(NameLoc, diag::ext_friend_tag_redecl_outside_namespace) << createFriendTagNNSFixIt(*this, ND, S, NameLoc); } } // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) return nullptr; if (!getLangOpts().CPlusPlus && TUK != TUK_Reference) { // FIXME: This makes sure that we ignore the contexts associated // with C structs, unions, and enums when looking for a matching // tag declaration or definition. See the similar lookup tweak // in Sema::LookupName; is there a better way to deal with this? while (isa(SearchDC) || isa(SearchDC)) SearchDC = SearchDC->getParent(); } } if (Previous.isSingleResult() && Previous.getFoundDecl()->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(NameLoc, Previous.getFoundDecl()); // Just pretend that we didn't see the previous declaration. Previous.clear(); } if (getLangOpts().CPlusPlus && Name && DC && StdNamespace && DC->Equals(getStdNamespace())) { if (Name->isStr("bad_alloc")) { // This is a declaration of or a reference to "std::bad_alloc". isStdBadAlloc = true; // If std::bad_alloc has been implicitly declared (but made invisible to // name lookup), fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. if (Previous.empty() && StdBadAlloc) Previous.addDecl(getStdBadAlloc()); } else if (Name->isStr("align_val_t")) { isStdAlignValT = true; if (Previous.empty() && StdAlignValT) Previous.addDecl(getStdAlignValT()); } } // If we didn't find a previous declaration, and this is a reference // (or friend reference), move to the correct scope. In C++, we // also need to do a redeclaration lookup there, just in case // there's a shadow friend decl. if (Name && Previous.empty() && (TUK == TUK_Reference || TUK == TUK_Friend)) { if (Invalid) goto CreateNewDecl; assert(SS.isEmpty()); if (TUK == TUK_Reference) { // C++ [basic.scope.pdecl]p5: // -- for an elaborated-type-specifier of the form // // class-key identifier // // if the elaborated-type-specifier is used in the // decl-specifier-seq or parameter-declaration-clause of a // function defined in namespace scope, the identifier is // declared as a class-name in the namespace that contains // the declaration; otherwise, except as a friend // declaration, the identifier is declared in the smallest // non-class, non-function-prototype scope that contains the // declaration. // // C99 6.7.2.3p8 has a similar (but not identical!) provision for // C structs and unions. // // It is an error in C++ to declare (rather than define) an enum // type, including via an elaborated type specifier. We'll // diagnose that later; for now, declare the enum in the same // scope as we would have picked for any other tag type. // // GNU C also supports this behavior as part of its incomplete // enum types extension, while GNU C++ does not. // // Find the context where we'll be declaring the tag. // FIXME: We would like to maintain the current DeclContext as the // lexical context, SearchDC = getTagInjectionContext(SearchDC); // Find the scope where we'll be declaring the tag. S = getTagInjectionScope(S, getLangOpts()); } else { assert(TUK == TUK_Friend); // C++ [namespace.memdef]p3: // If a friend declaration in a non-local class first declares a // class or function, the friend class or function is a member of // the innermost enclosing namespace. SearchDC = SearchDC->getEnclosingNamespaceContext(); } // In C++, we need to do a redeclaration lookup to properly // diagnose some problems. // FIXME: redeclaration lookup is also used (with and without C++) to find a // hidden declaration so that we don't get ambiguity errors when using a // type declared by an elaborated-type-specifier. In C that is not correct // and we should instead merge compatible types found by lookup. if (getLangOpts().CPlusPlus) { Previous.setRedeclarationKind(ForRedeclaration); LookupQualifiedName(Previous, SearchDC); } else { Previous.setRedeclarationKind(ForRedeclaration); LookupName(Previous, S); } } // If we have a known previous declaration to use, then use it. if (Previous.empty() && SkipBody && SkipBody->Previous) Previous.addDecl(SkipBody->Previous); if (!Previous.empty()) { NamedDecl *PrevDecl = Previous.getFoundDecl(); NamedDecl *DirectPrevDecl = Previous.getRepresentativeDecl(); // It's okay to have a tag decl in the same scope as a typedef // which hides a tag decl in the same scope. Finding this // insanity with a redeclaration lookup can only actually happen // in C++. // // This is also okay for elaborated-type-specifiers, which is // technically forbidden by the current standard but which is // okay according to the likely resolution of an open issue; // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 if (getLangOpts().CPlusPlus) { if (TypedefNameDecl *TD = dyn_cast(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs()) { TagDecl *Tag = TT->getDecl(); if (Tag->getDeclName() == Name && Tag->getDeclContext()->getRedeclContext() ->Equals(TD->getDeclContext()->getRedeclContext())) { PrevDecl = Tag; Previous.clear(); Previous.addDecl(Tag); Previous.resolveKind(); } } } } // If this is a redeclaration of a using shadow declaration, it must // declare a tag in the same context. In MSVC mode, we allow a // redefinition if either context is within the other. if (auto *Shadow = dyn_cast(DirectPrevDecl)) { auto *OldTag = dyn_cast(PrevDecl); if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend && isDeclInScope(Shadow, SearchDC, S, isMemberSpecialization) && !(OldTag && isAcceptableTagRedeclContext( *this, OldTag->getDeclContext(), SearchDC))) { Diag(KWLoc, diag::err_using_decl_conflict_reverse); Diag(Shadow->getTargetDecl()->getLocation(), diag::note_using_decl_target); Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; // Recover by ignoring the old declaration. Previous.clear(); goto CreateNewDecl; } } if (TagDecl *PrevTagDecl = dyn_cast(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. if (TUK == TUK_Reference || TUK == TUK_Friend || isDeclInScope(DirectPrevDecl, SearchDC, S, SS.isNotEmpty() || isMemberSpecialization)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, TUK == TUK_Definition, KWLoc, Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum); if (SafeToContinue) Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(SourceRange(KWLoc), PrevTagDecl->getKindName()); else Diag(KWLoc, diag::err_use_with_wrong_tag) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_use); if (SafeToContinue) Kind = PrevTagDecl->getTagKind(); else { // Recover by making this an anonymous redefinition. Name = nullptr; Previous.clear(); Invalid = true; } } if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) { const EnumDecl *PrevEnum = cast(PrevTagDecl); // If this is an elaborated-type-specifier for a scoped enumeration, // the 'class' keyword is not necessary and not permitted. if (TUK == TUK_Reference || TUK == TUK_Friend) { if (ScopedEnum) Diag(ScopedEnumKWLoc, diag::err_enum_class_reference) << PrevEnum->isScoped() << FixItHint::CreateRemoval(ScopedEnumKWLoc); return PrevTagDecl; } QualType EnumUnderlyingTy; if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast()) EnumUnderlyingTy = TI->getType().getUnqualifiedType(); else if (const Type *T = EnumUnderlying.dyn_cast()) EnumUnderlyingTy = QualType(T, 0); // All conflicts with previous declarations are recovered by // returning the previous declaration, unless this is a definition, // in which case we want the caller to bail out. if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc, ScopedEnum, EnumUnderlyingTy, EnumUnderlyingIsImplicit, PrevEnum)) return TUK == TUK_Declaration ? PrevTagDecl : nullptr; } // C++11 [class.mem]p1: // A member shall not be declared twice in the member-specification, // except that a nested class or member class template can be declared // and then later defined. if (TUK == TUK_Declaration && PrevDecl->isCXXClassMember() && S->isDeclScope(PrevDecl)) { Diag(NameLoc, diag::ext_member_redeclared); Diag(PrevTagDecl->getLocation(), diag::note_previous_declaration); } if (!Invalid) { // If this is a use, just return the declaration we found, unless // we have attributes. if (TUK == TUK_Reference || TUK == TUK_Friend) { if (Attr) { // FIXME: Diagnose these attributes. For now, we create a new // declaration to hold them. } else if (TUK == TUK_Reference && (PrevTagDecl->getFriendObjectKind() == Decl::FOK_Undeclared || PP.getModuleContainingLocation( PrevDecl->getLocation()) != PP.getModuleContainingLocation(KWLoc)) && SS.isEmpty()) { // This declaration is a reference to an existing entity, but // has different visibility from that entity: it either makes // a friend visible or it makes a type visible in a new module. // In either case, create a new declaration. We only do this if // the declaration would have meant the same thing if no prior // declaration were found, that is, if it was found in the same // scope where we would have injected a declaration. if (!getTagInjectionContext(CurContext)->getRedeclContext() ->Equals(PrevDecl->getDeclContext()->getRedeclContext())) return PrevTagDecl; // This is in the injected scope, create a new declaration in // that scope. S = getTagInjectionScope(S, getLangOpts()); } else { return PrevTagDecl; } } // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { if (NamedDecl *Def = PrevTagDecl->getDefinition()) { // If we're defining a specialization and the previous definition // is from an implicit instantiation, don't emit an error // here; we'll catch this in the general case below. bool IsExplicitSpecializationAfterInstantiation = false; if (isMemberSpecialization) { if (CXXRecordDecl *RD = dyn_cast(Def)) IsExplicitSpecializationAfterInstantiation = RD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization; else if (EnumDecl *ED = dyn_cast(Def)) IsExplicitSpecializationAfterInstantiation = ED->getTemplateSpecializationKind() != TSK_ExplicitSpecialization; } NamedDecl *Hidden = nullptr; if (SkipBody && getLangOpts().CPlusPlus && !hasVisibleDefinition(Def, &Hidden)) { // There is a definition of this tag, but it is not visible. We // explicitly make use of C++'s one definition rule here, and // assume that this definition is identical to the hidden one // we already have. Make the existing definition visible and // use it in place of this one. SkipBody->ShouldSkip = true; makeMergedDefinitionVisible(Hidden); return Def; } else if (!IsExplicitSpecializationAfterInstantiation) { // A redeclaration in function prototype scope in C isn't // visible elsewhere, so merely issue a warning. if (!getLangOpts().CPlusPlus && S->containedInPrototypeScope()) Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name; else Diag(NameLoc, diag::err_redefinition) << Name; notePreviousDefinition(Def->getLocation(), NameLoc.isValid() ? NameLoc : KWLoc); // If this is a redefinition, recover by making this // struct be anonymous, which will make any later // references get the previous definition. Name = nullptr; Previous.clear(); Invalid = true; } } else { // If the type is currently being defined, complain // about a nested redefinition. auto *TD = Context.getTagDeclType(PrevTagDecl)->getAsTagDecl(); if (TD->isBeingDefined()) { Diag(NameLoc, diag::err_nested_redefinition) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_definition); Name = nullptr; Previous.clear(); Invalid = true; } } // Okay, this is definition of a previously declared or referenced // tag. We're going to create a new Decl for it. } // Okay, we're going to make a redeclaration. If this is some kind // of reference, make sure we build the redeclaration in the same DC // as the original, and ignore the current access specifier. if (TUK == TUK_Friend || TUK == TUK_Reference) { SearchDC = PrevTagDecl->getDeclContext(); AS = AS_none; } } // If we get here we have (another) forward declaration or we // have a definition. Just create a new decl. } else { // If we get here, this is a definition of a new tag type in a nested // scope, e.g. "struct foo; void bar() { struct foo; }", just create a // new decl/type. We set PrevDecl to NULL so that the entities // have distinct types. Previous.clear(); } // If we get here, we're going to create a new Decl. If PrevDecl // is non-NULL, it's a definition of the tag declared by // PrevDecl. If it's NULL, we have a new definition. // Otherwise, PrevDecl is not a tag, but was found with tag // lookup. This is only actually possible in C++, where a few // things like templates still live in the tag namespace. } else { // Use a better diagnostic if an elaborated-type-specifier // found the wrong kind of type on the first // (non-redeclaration) lookup. if ((TUK == TUK_Reference || TUK == TUK_Friend) && !Previous.isForRedeclaration()) { NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind); Diag(NameLoc, diag::err_tag_reference_non_tag) << PrevDecl << NTK << Kind; Diag(PrevDecl->getLocation(), diag::note_declared_at); Invalid = true; // Otherwise, only diagnose if the declaration is in scope. } else if (!isDeclInScope(DirectPrevDecl, SearchDC, S, SS.isNotEmpty() || isMemberSpecialization)) { // do nothing // Diagnose implicit declarations introduced by elaborated types. } else if (TUK == TUK_Reference || TUK == TUK_Friend) { NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind); Diag(NameLoc, diag::err_tag_reference_conflict) << NTK; Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; Invalid = true; // Otherwise it's a declaration. Call out a particularly common // case here. } else if (TypedefNameDecl *TND = dyn_cast(PrevDecl)) { unsigned Kind = 0; if (isa(PrevDecl)) Kind = 1; Diag(NameLoc, diag::err_tag_definition_of_typedef) << Name << Kind << TND->getUnderlyingType(); Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; Invalid = true; // Otherwise, diagnose. } else { // The tag name clashes with something else in the target scope, // issue an error and recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; notePreviousDefinition(PrevDecl->getLocation(), NameLoc); Name = nullptr; Invalid = true; } // The existing declaration isn't relevant to us; we're in a // new scope, so clear out the previous declaration. Previous.clear(); } } CreateNewDecl: TagDecl *PrevDecl = nullptr; if (Previous.isSingleResult()) PrevDecl = cast(Previous.getFoundDecl()); // If there is an identifier, use the location of the identifier as the // location of the decl, otherwise use the location of the struct/union // keyword. SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc; // Otherwise, create a new declaration. If there is a previous // declaration of the same entity, the two will be linked via // PrevDecl. TagDecl *New; bool IsForwardReference = false; if (Kind == TTK_Enum) { // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // enum X { A, B, C } D; D should chain to X. New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, cast_or_null(PrevDecl), ScopedEnum, ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); if (isStdAlignValT && (!StdAlignValT || getStdAlignValT()->isImplicit())) StdAlignValT = cast(New); // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; if (!EnumUnderlyingIsImplicit && (getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) && cast(New)->isFixed()) { // C++0x: 7.2p2: opaque-enum-declaration. // Conflicts are diagnosed above. Do nothing. } else if (PrevDecl && (Def = cast(PrevDecl)->getDefinition())) { Diag(Loc, diag::ext_forward_ref_enum_def) << New; Diag(Def->getLocation(), diag::note_previous_definition); } else { unsigned DiagID = diag::ext_forward_ref_enum; if (getLangOpts().MSVCCompat) DiagID = diag::ext_ms_forward_ref_enum; else if (getLangOpts().CPlusPlus) DiagID = diag::err_forward_ref_enum; Diag(Loc, DiagID); // If this is a forward-declared reference to an enumeration, make a // note of it; we won't actually be introducing the declaration into // the declaration context. if (TUK == TUK_Reference) IsForwardReference = true; } } if (EnumUnderlying) { EnumDecl *ED = cast(New); if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast()) ED->setIntegerTypeSourceInfo(TI); else ED->setIntegerType(QualType(EnumUnderlying.get(), 0)); ED->setPromotionType(ED->getIntegerType()); } } else { // struct/union/class // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // struct X { int A; } D; D should chain to X. if (getLangOpts().CPlusPlus) { // FIXME: Look for a way to use RecordDecl for simple structs. New = CXXRecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, cast_or_null(PrevDecl)); if (isStdBadAlloc && (!StdBadAlloc || getStdBadAlloc()->isImplicit())) StdBadAlloc = cast(New); } else New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, cast_or_null(PrevDecl)); } // C++11 [dcl.type]p3: // A type-specifier-seq shall not define a class or enumeration [...]. if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) { Diag(New->getLocation(), diag::err_type_defined_in_type_specifier) << Context.getTagDeclType(New); Invalid = true; } // Maybe add qualifier info. if (SS.isNotEmpty()) { if (SS.isSet()) { // If this is either a declaration or a definition, check the // nested-name-specifier against the current context. We don't do this // for explicit specializations, because they have similar checking // (with more specific diagnostics) in the call to // CheckMemberSpecialization, below. if (!isMemberSpecialization && (TUK == TUK_Definition || TUK == TUK_Declaration) && diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc)) Invalid = true; New->setQualifierInfo(SS.getWithLocInContext(Context)); if (TemplateParameterLists.size() > 0) { New->setTemplateParameterListsInfo(Context, TemplateParameterLists); } } else Invalid = true; } if (RecordDecl *RD = dyn_cast(New)) { // Add alignment attributes if necessary; these attributes are checked when // the ASTContext lays out the structure. // // It is important for implementing the correct semantics that this // happen here (in act on tag decl). The #pragma pack stack is // maintained as a result of parser callbacks which can occur at // many points during the parsing of a struct declaration (because // the #pragma tokens are effectively skipped over during the // parsing of the struct). if (TUK == TUK_Definition) { AddAlignmentAttributesForRecord(RD); AddMsStructLayoutForRecord(RD); } } if (ModulePrivateLoc.isValid()) { if (isMemberSpecialization) Diag(New->getLocation(), diag::err_module_private_specialization) << 2 << FixItHint::CreateRemoval(ModulePrivateLoc); // __module_private__ does not apply to local classes. However, we only // diagnose this as an error when the declaration specifiers are // freestanding. Here, we just ignore the __module_private__. else if (!SearchDC->isFunctionOrMethod()) New->setModulePrivate(); } // If this is a specialization of a member class (of a class template), // check the specialization. if (isMemberSpecialization && CheckMemberSpecialization(New, Previous)) Invalid = true; // If we're declaring or defining a tag in function prototype scope in C, // note that this type can only be used within the function and add it to // the list of decls to inject into the function definition scope. if ((Name || Kind == TTK_Enum) && getNonFieldDeclScope(S)->isFunctionPrototypeScope()) { if (getLangOpts().CPlusPlus) { // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. if (TUK == TUK_Definition && !IsTypeSpecifier) { Diag(Loc, diag::err_type_defined_in_param_type) << Name; Invalid = true; } } else if (!PrevDecl) { Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); } } if (Invalid) New->setInvalidDecl(); // Set the lexical context. If the tag has a C++ scope specifier, the // lexical context will be different from the semantic context. New->setLexicalDeclContext(CurContext); // Mark this as a friend decl if applicable. // In Microsoft mode, a friend declaration also acts as a forward // declaration so we always pass true to setObjectOfFriendDecl to make // the tag name visible. if (TUK == TUK_Friend) New->setObjectOfFriendDecl(getLangOpts().MSVCCompat); // Set the access specifier. if (!Invalid && SearchDC->isRecord()) SetMemberAccessSpecifier(New, PrevDecl, AS); if (TUK == TUK_Definition) New->startDefinition(); if (Attr) ProcessDeclAttributeList(S, New, Attr); AddPragmaAttributes(S, New); // If this has an identifier, add it to the scope stack. if (TUK == TUK_Friend) { // We might be replacing an existing declaration in the lookup tables; // if so, borrow its access specifier. if (PrevDecl) New->setAccess(PrevDecl->getAccess()); DeclContext *DC = New->getDeclContext()->getRedeclContext(); DC->makeDeclVisibleInContext(New); if (Name) // can be null along some error paths if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); } else if (Name) { S = getNonFieldDeclScope(S); PushOnScopeChains(New, S, !IsForwardReference); if (IsForwardReference) SearchDC->makeDeclVisibleInContext(New); } else { CurContext->addDecl(New); } // If this is the C FILE type, notify the AST context. if (IdentifierInfo *II = New->getIdentifier()) if (!New->isInvalidDecl() && New->getDeclContext()->getRedeclContext()->isTranslationUnit() && II->isStr("FILE")) Context.setFILEDecl(New); if (PrevDecl) mergeDeclAttributes(New, PrevDecl); // If there's a #pragma GCC visibility in scope, set the visibility of this // record. AddPushedVisibilityAttribute(New); if (isMemberSpecialization && !New->isInvalidDecl()) CompleteMemberSpecialization(New, Previous); OwnedDecl = true; // In C++, don't return an invalid declaration. We can't recover well from // the cases where we make the type anonymous. if (Invalid && getLangOpts().CPlusPlus) { if (New->isBeingDefined()) if (auto RD = dyn_cast(New)) RD->completeDefinition(); return nullptr; } else { return New; } } void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); // Enter the tag context. PushDeclContext(S, Tag); ActOnDocumentableDecl(TagD); // If there's a #pragma GCC visibility in scope, set the visibility of this // record. AddPushedVisibilityAttribute(Tag); } Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { assert(isa(IDecl) && "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); DeclContext *OCD = cast(IDecl); assert(getContainingDC(OCD) == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = OCD; return IDecl; } void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, SourceLocation FinalLoc, bool IsFinalSpelledSealed, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast(TagD); FieldCollector->StartClass(); if (!Record->getIdentifier()) return; if (FinalLoc.isValid()) Record->addAttr(new (Context) FinalAttr(FinalLoc, Context, IsFinalSpelledSealed)); // C++ [class]p2: // [...] The class-name is also inserted into the scope of the // class itself; this is known as the injected-class-name. For // purposes of access checking, the injected-class-name is treated // as if it were a public member name. CXXRecordDecl *InjectedClassName = CXXRecordDecl::Create(Context, Record->getTagKind(), CurContext, Record->getLocStart(), Record->getLocation(), Record->getIdentifier(), /*PrevDecl=*/nullptr, /*DelayTypeCreation=*/true); Context.getTypeDeclType(InjectedClassName, Record); InjectedClassName->setImplicit(); InjectedClassName->setAccess(AS_public); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) InjectedClassName->setDescribedClassTemplate(Template); PushOnScopeChains(InjectedClassName, S); assert(InjectedClassName->isInjectedClassName() && "Broken injected-class-name"); } void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, SourceRange BraceRange) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); Tag->setBraceRange(BraceRange); // Make sure we "complete" the definition even it is invalid. if (Tag->isBeingDefined()) { assert(Tag->isInvalidDecl() && "We should already have completed it"); if (RecordDecl *RD = dyn_cast(Tag)) RD->completeDefinition(); } if (isa(Tag)) { FieldCollector->FinishClass(); } // Exit this scope of this tag's definition. PopDeclContext(); if (getCurLexicalContext()->isObjCContainer() && Tag->getDeclContext()->isFileContext()) Tag->setTopLevelDeclInObjCContainer(); // Notify the consumer that we've defined a tag. if (!Tag->isInvalidDecl()) Consumer.HandleTagDeclDefinition(Tag); } void Sema::ActOnObjCContainerFinishDefinition() { // Exit this scope of this interface definition. PopDeclContext(); } void Sema::ActOnObjCTemporaryExitContainerContext(DeclContext *DC) { assert(DC == CurContext && "Mismatch of container contexts"); OriginalLexicalContext = DC; ActOnObjCContainerFinishDefinition(); } void Sema::ActOnObjCReenterContainerContext(DeclContext *DC) { ActOnObjCContainerStartDefinition(cast(DC)); OriginalLexicalContext = nullptr; } void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); Tag->setInvalidDecl(); // Make sure we "complete" the definition even it is invalid. if (Tag->isBeingDefined()) { if (RecordDecl *RD = dyn_cast(Tag)) RD->completeDefinition(); } // We're undoing ActOnTagStartDefinition here, not // ActOnStartCXXMemberDeclarations, so we don't have to mess with // the FieldCollector. PopDeclContext(); } // Note that FieldName may be null for anonymous bitfields. ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, bool IsMsStruct, Expr *BitWidth, bool *ZeroWidth) { // Default to true; that shouldn't confuse checks for emptiness if (ZeroWidth) *ZeroWidth = true; // C99 6.7.2.1p4 - verify the field type. // C++ 9.6p3: A bit-field shall have integral or enumeration type. if (!FieldTy->isDependentType() && !FieldTy->isIntegralOrEnumerationType()) { // Handle incomplete types with specific error. if (RequireCompleteType(FieldLoc, FieldTy, diag::err_field_incomplete)) return ExprError(); if (FieldName) return Diag(FieldLoc, diag::err_not_integral_type_bitfield) << FieldName << FieldTy << BitWidth->getSourceRange(); return Diag(FieldLoc, diag::err_not_integral_type_anon_bitfield) << FieldTy << BitWidth->getSourceRange(); } else if (DiagnoseUnexpandedParameterPack(const_cast(BitWidth), UPPC_BitFieldWidth)) return ExprError(); // If the bit-width is type- or value-dependent, don't try to check // it now. if (BitWidth->isValueDependent() || BitWidth->isTypeDependent()) return BitWidth; llvm::APSInt Value; ExprResult ICE = VerifyIntegerConstantExpression(BitWidth, &Value); if (ICE.isInvalid()) return ICE; BitWidth = ICE.get(); if (Value != 0 && ZeroWidth) *ZeroWidth = false; // Zero-width bitfield is ok for anonymous field. if (Value == 0 && FieldName) return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName; if (Value.isSigned() && Value.isNegative()) { if (FieldName) return Diag(FieldLoc, diag::err_bitfield_has_negative_width) << FieldName << Value.toString(10); return Diag(FieldLoc, diag::err_anon_bitfield_has_negative_width) << Value.toString(10); } if (!FieldTy->isDependentType()) { uint64_t TypeStorageSize = Context.getTypeSize(FieldTy); uint64_t TypeWidth = Context.getIntWidth(FieldTy); bool BitfieldIsOverwide = Value.ugt(TypeWidth); // Over-wide bitfields are an error in C or when using the MSVC bitfield // ABI. bool CStdConstraintViolation = BitfieldIsOverwide && !getLangOpts().CPlusPlus; bool MSBitfieldViolation = Value.ugt(TypeStorageSize) && (IsMsStruct || Context.getTargetInfo().getCXXABI().isMicrosoft()); if (CStdConstraintViolation || MSBitfieldViolation) { unsigned DiagWidth = CStdConstraintViolation ? TypeWidth : TypeStorageSize; if (FieldName) return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_width) << FieldName << (unsigned)Value.getZExtValue() << !CStdConstraintViolation << DiagWidth; return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_width) << (unsigned)Value.getZExtValue() << !CStdConstraintViolation << DiagWidth; } // Warn on types where the user might conceivably expect to get all // specified bits as value bits: that's all integral types other than // 'bool'. if (BitfieldIsOverwide && !FieldTy->isBooleanType()) { if (FieldName) Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_width) << FieldName << (unsigned)Value.getZExtValue() << (unsigned)TypeWidth; else Diag(FieldLoc, diag::warn_anon_bitfield_width_exceeds_type_width) << (unsigned)Value.getZExtValue() << (unsigned)TypeWidth; } } return BitWidth; } /// ActOnField - Each field of a C struct/union is passed into this in order /// to create a FieldDecl object for it. Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null(TagD), DeclStart, D, static_cast(BitfieldWidth), /*InitStyle=*/ICIS_NoInit, AS_public); return Res; } /// HandleField - Analyze a field of a C struct or a C++ data member. /// FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, SourceLocation DeclStart, Declarator &D, Expr *BitWidth, InClassInitStyle InitStyle, AccessSpecifier AS) { if (D.isDecompositionDeclarator()) { const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator(); Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context) << Decomp.getSourceRange(); return nullptr; } IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); if (getLangOpts().CPlusPlus) { CheckExtraCXXDefaultArguments(D); if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DataMemberType)) { D.setInvalidType(); T = Context.IntTy; TInfo = Context.getTrivialTypeSourceInfo(T, Loc); } } // TR 18037 does not allow fields to be declared with address spaces. if (T.getQualifiers().hasAddressSpace()) { Diag(Loc, diag::err_field_with_address_space); D.setInvalidType(); } // OpenCL v1.2 s6.9b,r & OpenCL v2.0 s6.12.5 - The following types cannot be // used as structure or union field: image, sampler, event or block types. if (LangOpts.OpenCL && (T->isEventT() || T->isImageType() || T->isSamplerT() || T->isBlockPointerType())) { Diag(Loc, diag::err_opencl_type_struct_or_union_field) << T; D.setInvalidType(); } DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (D.getDeclSpec().isInlineSpecified()) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) << getLangOpts().CPlusPlus1z; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = nullptr; LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); LookupName(Previous, S); switch (Previous.getResultKind()) { case LookupResult::Found: case LookupResult::FoundUnresolvedValue: PrevDecl = Previous.getAsSingle(); break; case LookupResult::FoundOverloaded: PrevDecl = Previous.getRepresentativeDecl(); break; case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: break; } Previous.suppressDiagnostics(); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); // Just pretend that we didn't see the previous declaration. PrevDecl = nullptr; } if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) PrevDecl = nullptr; bool Mutable = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getLocStart(); FieldDecl *NewFD = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, InitStyle, TSSL, AS, PrevDecl, &D); if (NewFD->isInvalidDecl()) Record->setInvalidDecl(); if (D.getDeclSpec().isModulePrivateSpecified()) NewFD->setModulePrivate(); if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something // with the same name in the same scope. } else if (II) { PushOnScopeChains(NewFD, S); } else Record->addDecl(NewFD); return NewFD; } /// \brief Build a new FieldDecl and check its well-formedness. /// /// This routine builds a new FieldDecl given the fields name, type, /// record, etc. \p PrevDecl should refer to any previous declaration /// with the same name and in the same scope as the field to be /// created. /// /// \returns a new FieldDecl. /// /// \todo The Declarator argument is a hack. It will be removed once FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitWidth, InClassInitStyle InitStyle, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { IdentifierInfo *II = Name.getAsIdentifierInfo(); bool InvalidDecl = false; if (D) InvalidDecl = D->isInvalidType(); // If we receive a broken type, recover by assuming 'int' and // marking this declaration as invalid. if (T.isNull()) { InvalidDecl = true; T = Context.IntTy; } QualType EltTy = Context.getBaseElementType(T); if (!EltTy->isDependentType()) { if (RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) { // Fields of incomplete type force their record to be invalid. Record->setInvalidDecl(); InvalidDecl = true; } else { NamedDecl *Def; EltTy->isIncompleteType(&Def); if (Def && Def->isInvalidDecl()) { Record->setInvalidDecl(); InvalidDecl = true; } } } // OpenCL v1.2 s6.9.c: bitfields are not supported. if (BitWidth && getLangOpts().OpenCL) { Diag(Loc, diag::err_opencl_bitfields); InvalidDecl = true; } // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. if (!InvalidDecl && T->isVariablyModifiedType()) { bool SizeIsNegative; llvm::APSInt Oversized; TypeSourceInfo *FixedTInfo = TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, SizeIsNegative, Oversized); if (FixedTInfo) { Diag(Loc, diag::warn_illegal_constant_array_size); TInfo = FixedTInfo; T = FixedTInfo->getType(); } else { if (SizeIsNegative) Diag(Loc, diag::err_typecheck_negative_array_size); else if (Oversized.getBoolValue()) Diag(Loc, diag::err_array_too_large) << Oversized.toString(10); else Diag(Loc, diag::err_typecheck_field_variable_size); InvalidDecl = true; } } // Fields can not have abstract class types if (!InvalidDecl && RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl, AbstractFieldType)) InvalidDecl = true; bool ZeroWidth = false; if (InvalidDecl) BitWidth = nullptr; // If this is declared as a bit-field, check the bit-field. if (BitWidth) { BitWidth = VerifyBitField(Loc, II, T, Record->isMsStruct(Context), BitWidth, &ZeroWidth).get(); if (!BitWidth) { InvalidDecl = true; BitWidth = nullptr; ZeroWidth = false; } } // Check that 'mutable' is consistent with the type of the declaration. if (!InvalidDecl && Mutable) { unsigned DiagID = 0; if (T->isReferenceType()) DiagID = getLangOpts().MSVCCompat ? diag::ext_mutable_reference : diag::err_mutable_reference; else if (T.isConstQualified()) DiagID = diag::err_mutable_const; if (DiagID) { SourceLocation ErrLoc = Loc; if (D && D->getDeclSpec().getStorageClassSpecLoc().isValid()) ErrLoc = D->getDeclSpec().getStorageClassSpecLoc(); Diag(ErrLoc, DiagID); if (DiagID != diag::ext_mutable_reference) { Mutable = false; InvalidDecl = true; } } } // C++11 [class.union]p8 (DR1460): // At most one variant member of a union may have a // brace-or-equal-initializer. if (InitStyle != ICIS_NoInit) checkDuplicateDefaultInit(*this, cast(Record), Loc); FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, BitWidth, Mutable, InitStyle); if (InvalidDecl) NewFD->setInvalidDecl(); if (PrevDecl && !isa(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); } if (!InvalidDecl && getLangOpts().CPlusPlus) { if (Record->isUnion()) { if (const RecordType *RT = EltTy->getAs()) { CXXRecordDecl* RDecl = cast(RT->getDecl()); if (RDecl->getDefinition()) { // C++ [class.union]p1: An object of a class with a non-trivial // constructor, a non-trivial copy constructor, a non-trivial // destructor, or a non-trivial copy assignment operator // cannot be a member of a union, nor can an array of such // objects. if (CheckNontrivialField(NewFD)) NewFD->setInvalidDecl(); } } // C++ [class.union]p1: If a union contains a member of reference type, // the program is ill-formed, except when compiling with MSVC extensions // enabled. if (EltTy->isReferenceType()) { Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? diag::ext_union_member_of_reference_type : diag::err_union_member_of_reference_type) << NewFD->getDeclName() << EltTy; if (!getLangOpts().MicrosoftExt) NewFD->setInvalidDecl(); } } } // FIXME: We need to pass in the attributes given an AST // representation, not a parser representation. if (D) { // FIXME: The current scope is almost... but not entirely... correct here. ProcessDeclAttributes(getCurScope(), NewFD, *D); if (NewFD->hasAttrs()) CheckAlignasUnderalignment(NewFD); } // In auto-retain/release, infer strong retension for fields of // retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewFD)) NewFD->setInvalidDecl(); if (T.isObjCGCWeak()) Diag(Loc, diag::warn_attribute_weak_on_field); NewFD->setAccess(AS); return NewFD; } bool Sema::CheckNontrivialField(FieldDecl *FD) { assert(FD); assert(getLangOpts().CPlusPlus && "valid check only for C++"); if (FD->isInvalidDecl() || FD->getType()->isDependentType()) return false; QualType EltTy = Context.getBaseElementType(FD->getType()); if (const RecordType *RT = EltTy->getAs()) { CXXRecordDecl *RDecl = cast(RT->getDecl()); if (RDecl->getDefinition()) { // We check for copy constructors before constructors // because otherwise we'll never get complaints about // copy constructors. CXXSpecialMember member = CXXInvalid; // We're required to check for any non-trivial constructors. Since the // implicit default constructor is suppressed if there are any // user-declared constructors, we just need to check that there is a // trivial default constructor and a trivial copy constructor. (We don't // worry about move constructors here, since this is a C++98 check.) if (RDecl->hasNonTrivialCopyConstructor()) member = CXXCopyConstructor; else if (!RDecl->hasTrivialDefaultConstructor()) member = CXXDefaultConstructor; else if (RDecl->hasNonTrivialCopyAssignment()) member = CXXCopyAssignment; else if (RDecl->hasNonTrivialDestructor()) member = CXXDestructor; if (member != CXXInvalid) { if (!getLangOpts().CPlusPlus11 && getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) { // Objective-C++ ARC: it is an error to have a non-trivial field of // a union. However, system headers in Objective-C programs // occasionally have Objective-C lifetime objects within unions, // and rather than cause the program to fail, we make those // members unavailable. SourceLocation Loc = FD->getLocation(); if (getSourceManager().isInSystemHeader(Loc)) { if (!FD->hasAttr()) FD->addAttr(UnavailableAttr::CreateImplicit(Context, "", UnavailableAttr::IR_ARCFieldWithOwnership, Loc)); return false; } } Diag(FD->getLocation(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member : diag::err_illegal_union_or_anon_struct_member) << FD->getParent()->isUnion() << FD->getDeclName() << member; DiagnoseNontrivial(RDecl, member); return !getLangOpts().CPlusPlus11; } } } return false; } /// TranslateIvarVisibility - Translate visibility from a token ID to an /// AST enum value. static ObjCIvarDecl::AccessControl TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { switch (ivarVisibility) { default: llvm_unreachable("Unknown visitibility kind"); case tok::objc_private: return ObjCIvarDecl::Private; case tok::objc_public: return ObjCIvarDecl::Public; case tok::objc_protected: return ObjCIvarDecl::Protected; case tok::objc_package: return ObjCIvarDecl::Package; } } /// ActOnIvar - Each ivar field of an objective-c class is passed into this /// in order to create an IvarDecl object for it. Decl *Sema::ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, tok::ObjCKeywordKind Visibility) { IdentifierInfo *II = D.getIdentifier(); Expr *BitWidth = (Expr*)BitfieldWidth; SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); // FIXME: Unnamed fields can be handled in various different ways, for // example, unnamed unions inject all members into the struct namespace! TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); if (BitWidth) { // 6.7.2.1p3, 6.7.2.1p4 BitWidth = VerifyBitField(Loc, II, T, /*IsMsStruct*/false, BitWidth).get(); if (!BitWidth) D.setInvalidType(); } else { // Not a bitfield. // validate II. } if (T->isReferenceType()) { Diag(Loc, diag::err_ivar_reference_type); D.setInvalidType(); } // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. else if (T->isVariablyModifiedType()) { Diag(Loc, diag::err_typecheck_ivar_variable_size); D.setInvalidType(); } // Get the visibility (access control) for this ivar. ObjCIvarDecl::AccessControl ac = Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility) : ObjCIvarDecl::None; // Must set ivar's DeclContext to its enclosing interface. ObjCContainerDecl *EnclosingDecl = cast(CurContext); if (!EnclosingDecl || EnclosingDecl->isInvalidDecl()) return nullptr; ObjCContainerDecl *EnclosingContext; if (ObjCImplementationDecl *IMPDecl = dyn_cast(EnclosingDecl)) { if (LangOpts.ObjCRuntime.isFragile()) { // Case of ivar declared in an implementation. Context is that of its class. EnclosingContext = IMPDecl->getClassInterface(); assert(EnclosingContext && "Implementation has no class interface!"); } else EnclosingContext = EnclosingDecl; } else { if (ObjCCategoryDecl *CDecl = dyn_cast(EnclosingDecl)) { if (LangOpts.ObjCRuntime.isFragile() || !CDecl->IsClassExtension()) { Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); return nullptr; } } EnclosingContext = EnclosingDecl; } // Construct the decl. ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, EnclosingContext, DeclStart, Loc, II, T, TInfo, ac, (Expr *)BitfieldWidth); if (II) { NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, ForRedeclaration); if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); NewID->setInvalidDecl(); } } // Process attributes attached to the ivar. ProcessDeclAttributes(S, NewID, D); if (D.isInvalidType()) NewID->setInvalidDecl(); // In ARC, infer 'retaining' for ivars of retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewID)) NewID->setInvalidDecl(); if (D.getDeclSpec().isModulePrivateSpecified()) NewID->setModulePrivate(); if (II) { // FIXME: When interfaces are DeclContexts, we'll need to add // these to the interface. S->AddDecl(NewID); IdResolver.AddDecl(NewID); } if (LangOpts.ObjCRuntime.isNonFragile() && !NewID->isInvalidDecl() && isa(EnclosingDecl)) Diag(Loc, diag::warn_ivars_in_interface); return NewID; } /// ActOnLastBitfield - This routine handles synthesized bitfields rules for /// class and class extensions. For every class \@interface and class /// extension \@interface, if the last ivar is a bitfield of any type, /// then add an implicit `char :0` ivar to the end of that interface. void Sema::ActOnLastBitfield(SourceLocation DeclLoc, SmallVectorImpl &AllIvarDecls) { if (LangOpts.ObjCRuntime.isFragile() || AllIvarDecls.empty()) return; Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1]; ObjCIvarDecl *Ivar = cast(ivarDecl); if (!Ivar->isBitField() || Ivar->getBitWidthValue(Context) == 0) return; ObjCInterfaceDecl *ID = dyn_cast(CurContext); if (!ID) { if (ObjCCategoryDecl *CD = dyn_cast(CurContext)) { if (!CD->IsClassExtension()) return; } // No need to add this to end of @implementation. else return; } // All conditions are met. Add a new bitfield to the tail end of ivars. llvm::APInt Zero(Context.getTypeSize(Context.IntTy), 0); Expr * BW = IntegerLiteral::Create(Context, Zero, Context.IntTy, DeclLoc); Ivar = ObjCIvarDecl::Create(Context, cast(CurContext), DeclLoc, DeclLoc, nullptr, Context.CharTy, Context.getTrivialTypeSourceInfo(Context.CharTy, DeclLoc), ObjCIvarDecl::Private, BW, true); AllIvarDecls.push_back(Ivar); } void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, ArrayRef Fields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *Attr) { assert(EnclosingDecl && "missing record or interface decl"); // If this is an Objective-C @implementation or category and we have // new fields here we should reset the layout of the interface since // it will now change. if (!Fields.empty() && isa(EnclosingDecl)) { ObjCContainerDecl *DC = cast(EnclosingDecl); switch (DC->getKind()) { default: break; case Decl::ObjCCategory: Context.ResetObjCLayout(cast(DC)->getClassInterface()); break; case Decl::ObjCImplementation: Context. ResetObjCLayout(cast(DC)->getClassInterface()); break; } } RecordDecl *Record = dyn_cast(EnclosingDecl); // Start counting up the number of named members; make sure to include // members of anonymous structs and unions in the total. unsigned NumNamedMembers = 0; if (Record) { for (const auto *I : Record->decls()) { if (const auto *IFD = dyn_cast(I)) if (IFD->getDeclName()) ++NumNamedMembers; } } // Verify that all the fields are okay. SmallVector RecFields; bool ObjCFieldLifetimeErrReported = false; for (ArrayRef::iterator i = Fields.begin(), end = Fields.end(); i != end; ++i) { FieldDecl *FD = cast(*i); // Get the type for the field. const Type *FDTy = FD->getType().getTypePtr(); if (!FD->isAnonymousStructOrUnion()) { // Remember all fields written by the user. RecFields.push_back(FD); } // If the field is already invalid for some reason, don't emit more // diagnostics about it. if (FD->isInvalidDecl()) { EnclosingDecl->setInvalidDecl(); continue; } // C99 6.7.2.1p2: // A structure or union shall not contain a member with // incomplete or function type (hence, a structure shall not // contain an instance of itself, but may contain a pointer to // an instance of itself), except that the last member of a // structure with more than one named member may have incomplete // array type; such a structure (and any union containing, // possibly recursively, a member that is such a structure) // shall not be a member of a structure or an element of an // array. if (FDTy->isFunctionType()) { // Field declared as a function. Diag(FD->getLocation(), diag::err_field_declared_as_function) << FD->getDeclName(); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; } else if (FDTy->isIncompleteArrayType() && Record && ((i + 1 == Fields.end() && !Record->isUnion()) || ((getLangOpts().MicrosoftExt || getLangOpts().CPlusPlus) && (i + 1 == Fields.end() || Record->isUnion())))) { // Flexible array member. // Microsoft and g++ is more permissive regarding flexible array. // It will accept flexible array in union and also // as the sole element of a struct/class. unsigned DiagID = 0; if (Record->isUnion()) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_union_ms : getLangOpts().CPlusPlus ? diag::ext_flexible_array_union_gnu : diag::err_flexible_array_union; else if (NumNamedMembers < 1) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_empty_aggregate_ms : getLangOpts().CPlusPlus ? diag::ext_flexible_array_empty_aggregate_gnu : diag::err_flexible_array_empty_aggregate; if (DiagID) Diag(FD->getLocation(), DiagID) << FD->getDeclName() << Record->getTagKind(); // While the layout of types that contain virtual bases is not specified // by the C++ standard, both the Itanium and Microsoft C++ ABIs place // virtual bases after the derived members. This would make a flexible // array member declared at the end of an object not adjacent to the end // of the type. if (CXXRecordDecl *RD = dyn_cast(Record)) if (RD->getNumVBases() != 0) Diag(FD->getLocation(), diag::err_flexible_array_virtual_base) << FD->getDeclName() << Record->getTagKind(); if (!getLangOpts().C99) Diag(FD->getLocation(), diag::ext_c99_flexible_array_member) << FD->getDeclName() << Record->getTagKind(); // If the element type has a non-trivial destructor, we would not // implicitly destroy the elements, so disallow it for now. // // FIXME: GCC allows this. We should probably either implicitly delete // the destructor of the containing class, or just allow this. QualType BaseElem = Context.getBaseElementType(FD->getType()); if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) { Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor) << FD->getDeclName() << FD->getType(); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; } // Okay, we have a legal flexible array member at the end of the struct. Record->setHasFlexibleArrayMember(true); } else if (!FDTy->isDependentType() && RequireCompleteType(FD->getLocation(), FD->getType(), diag::err_field_incomplete)) { // Incomplete type FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; } else if (const RecordType *FDTTy = FDTy->getAs()) { if (Record && FDTTy->getDecl()->hasFlexibleArrayMember()) { // A type which contains a flexible array member is considered to be a // flexible array member. Record->setHasFlexibleArrayMember(true); if (!Record->isUnion()) { // If this is a struct/class and this is not the last element, reject // it. Note that GCC supports variable sized arrays in the middle of // structures. if (i + 1 != Fields.end()) Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct) << FD->getDeclName() << FD->getType(); else { // We support flexible arrays at the end of structs in // other structs as an extension. Diag(FD->getLocation(), diag::ext_flexible_array_in_struct) << FD->getDeclName(); } } } if (isa(EnclosingDecl) && RequireNonAbstractType(FD->getLocation(), FD->getType(), diag::err_abstract_type_in_decl, AbstractIvarType)) { // Ivars can not have abstract class types FD->setInvalidDecl(); } if (Record && FDTTy->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); if (Record && FDTTy->getDecl()->hasVolatileMember()) Record->setHasVolatileMember(true); } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object) << FixItHint::CreateInsertion(FD->getLocation(), "*"); QualType T = Context.getObjCObjectPointerType(FD->getType()); FD->setType(T); } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && Record && !ObjCFieldLifetimeErrReported && (!getLangOpts().CPlusPlus || Record->isUnion())) { // It's an error in ARC or Weak if a field has lifetime. // We don't want to report this in a system header, though, // so we just make the field unavailable. // FIXME: that's really not sufficient; we need to make the type // itself invalid to, say, initialize or copy. QualType T = FD->getType(); if (T.hasNonTrivialObjCLifetime()) { SourceLocation loc = FD->getLocation(); if (getSourceManager().isInSystemHeader(loc)) { if (!FD->hasAttr()) { FD->addAttr(UnavailableAttr::CreateImplicit(Context, "", UnavailableAttr::IR_ARCFieldWithOwnership, loc)); } } else { Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag) << T->isBlockPointerType() << Record->getTagKind(); } ObjCFieldLifetimeErrReported = true; } } else if (getLangOpts().ObjC1 && getLangOpts().getGC() != LangOptions::NonGC && Record && !Record->hasObjectMember()) { if (FD->getType()->isObjCObjectPointerType() || FD->getType().isObjCGCStrong()) Record->setHasObjectMember(true); else if (Context.getAsArrayType(FD->getType())) { QualType BaseType = Context.getBaseElementType(FD->getType()); if (BaseType->isRecordType() && BaseType->getAs()->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); else if (BaseType->isObjCObjectPointerType() || BaseType.isObjCGCStrong()) Record->setHasObjectMember(true); } } if (Record && FD->getType().isVolatileQualified()) Record->setHasVolatileMember(true); // Keep track of the number of named members. if (FD->getIdentifier()) ++NumNamedMembers; } // Okay, we successfully defined 'Record'. if (Record) { bool Completed = false; if (CXXRecordDecl *CXXRecord = dyn_cast(Record)) { if (!CXXRecord->isInvalidDecl()) { // Set access bits correctly on the directly-declared conversions. for (CXXRecordDecl::conversion_iterator I = CXXRecord->conversion_begin(), E = CXXRecord->conversion_end(); I != E; ++I) I.setAccess((*I)->getAccess()); } if (!CXXRecord->isDependentType()) { if (CXXRecord->hasUserDeclaredDestructor()) { // Adjust user-defined destructor exception spec. if (getLangOpts().CPlusPlus11) AdjustDestructorExceptionSpec(CXXRecord, CXXRecord->getDestructor()); } if (!CXXRecord->isInvalidDecl()) { // Add any implicitly-declared members to this class. AddImplicitlyDeclaredMembersToClass(CXXRecord); // If we have virtual base classes, we may end up finding multiple // final overriders for a given virtual function. Check for this // problem now. if (CXXRecord->getNumVBases()) { CXXFinalOverriderMap FinalOverriders; CXXRecord->getFinalOverriders(FinalOverriders); for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), MEnd = FinalOverriders.end(); M != MEnd; ++M) { for (OverridingMethods::iterator SO = M->second.begin(), SOEnd = M->second.end(); SO != SOEnd; ++SO) { assert(SO->second.size() > 0 && "Virtual function without overridding functions?"); if (SO->second.size() == 1) continue; // C++ [class.virtual]p2: // In a derived class, if a virtual member function of a base // class subobject has more than one final overrider the // program is ill-formed. Diag(Record->getLocation(), diag::err_multiple_final_overriders) << (const NamedDecl *)M->first << Record; Diag(M->first->getLocation(), diag::note_overridden_virtual_function); for (OverridingMethods::overriding_iterator OM = SO->second.begin(), OMEnd = SO->second.end(); OM != OMEnd; ++OM) Diag(OM->Method->getLocation(), diag::note_final_overrider) << (const NamedDecl *)M->first << OM->Method->getParent(); Record->setInvalidDecl(); } } CXXRecord->completeDefinition(&FinalOverriders); Completed = true; } } } } if (!Completed) Record->completeDefinition(); // We may have deferred checking for a deleted destructor. Check now. if (CXXRecordDecl *CXXRecord = dyn_cast(Record)) { auto *Dtor = CXXRecord->getDestructor(); if (Dtor && Dtor->isImplicit() && ShouldDeleteSpecialMember(Dtor, CXXDestructor)) SetDeclDeleted(Dtor, CXXRecord->getLocation()); } if (Record->hasAttrs()) { CheckAlignasUnderalignment(Record); if (const MSInheritanceAttr *IA = Record->getAttr()) checkMSInheritanceAttrOnDefinition(cast(Record), IA->getRange(), IA->getBestCase(), IA->getSemanticSpelling()); } // Check if the structure/union declaration is a type that can have zero // size in C. For C this is a language extension, for C++ it may cause // compatibility problems. bool CheckForZeroSize; if (!getLangOpts().CPlusPlus) { CheckForZeroSize = true; } else { // For C++ filter out types that cannot be referenced in C code. CXXRecordDecl *CXXRecord = cast(Record); CheckForZeroSize = CXXRecord->getLexicalDeclContext()->isExternCContext() && !CXXRecord->isDependentType() && CXXRecord->isCLike(); } if (CheckForZeroSize) { bool ZeroSize = true; bool IsEmpty = true; unsigned NonBitFields = 0; for (RecordDecl::field_iterator I = Record->field_begin(), E = Record->field_end(); (NonBitFields == 0 || ZeroSize) && I != E; ++I) { IsEmpty = false; if (I->isUnnamedBitfield()) { if (I->getBitWidthValue(Context) > 0) ZeroSize = false; } else { ++NonBitFields; QualType FieldType = I->getType(); if (FieldType->isIncompleteType() || !Context.getTypeSizeInChars(FieldType).isZero()) ZeroSize = false; } } // Empty structs are an extension in C (C99 6.7.2.1p7). They are // allowed in C++, but warn if its declaration is inside // extern "C" block. if (ZeroSize) { Diag(RecLoc, getLangOpts().CPlusPlus ? diag::warn_zero_size_struct_union_in_extern_c : diag::warn_zero_size_struct_union_compat) << IsEmpty << Record->isUnion() << (NonBitFields > 1); } // Structs without named members are extension in C (C99 6.7.2.1p7), // but are accepted by GCC. if (NonBitFields == 0 && !getLangOpts().CPlusPlus) { Diag(RecLoc, IsEmpty ? diag::ext_empty_struct_union : diag::ext_no_named_members_in_struct_union) << Record->isUnion(); } } } else { ObjCIvarDecl **ClsFields = reinterpret_cast(RecFields.data()); if (ObjCInterfaceDecl *ID = dyn_cast(EnclosingDecl)) { ID->setEndOfDefinitionLoc(RBrac); // Add ivar's to class's DeclContext. for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { ClsFields[i]->setLexicalDeclContext(ID); ID->addDecl(ClsFields[i]); } // Must enforce the rule that ivars in the base classes may not be // duplicates. if (ID->getSuperClass()) DiagnoseDuplicateIvars(ID, ID->getSuperClass()); } else if (ObjCImplementationDecl *IMPDecl = dyn_cast(EnclosingDecl)) { assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); for (unsigned I = 0, N = RecFields.size(); I != N; ++I) // Ivar declared in @implementation never belongs to the implementation. // Only it is in implementation's lexical context. ClsFields[I]->setLexicalDeclContext(IMPDecl); CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); IMPDecl->setIvarLBraceLoc(LBrac); IMPDecl->setIvarRBraceLoc(RBrac); } else if (ObjCCategoryDecl *CDecl = dyn_cast(EnclosingDecl)) { // case of ivars in class extension; all other cases have been // reported as errors elsewhere. // FIXME. Class extension does not have a LocEnd field. // CDecl->setLocEnd(RBrac); // Add ivar's to class extension's DeclContext. // Diagnose redeclaration of private ivars. ObjCInterfaceDecl *IDecl = CDecl->getClassInterface(); for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { if (IDecl) { if (const ObjCIvarDecl *ClsIvar = IDecl->getIvarDecl(ClsFields[i]->getIdentifier())) { Diag(ClsFields[i]->getLocation(), diag::err_duplicate_ivar_declaration); Diag(ClsIvar->getLocation(), diag::note_previous_definition); continue; } for (const auto *Ext : IDecl->known_extensions()) { if (const ObjCIvarDecl *ClsExtIvar = Ext->getIvarDecl(ClsFields[i]->getIdentifier())) { Diag(ClsFields[i]->getLocation(), diag::err_duplicate_ivar_declaration); Diag(ClsExtIvar->getLocation(), diag::note_previous_definition); continue; } } } ClsFields[i]->setLexicalDeclContext(CDecl); CDecl->addDecl(ClsFields[i]); } CDecl->setIvarLBraceLoc(LBrac); CDecl->setIvarRBraceLoc(RBrac); } } if (Attr) ProcessDeclAttributeList(S, Record, Attr); } /// \brief Determine whether the given integral value is representable within /// the given type T. static bool isRepresentableIntegerValue(ASTContext &Context, llvm::APSInt &Value, QualType T) { assert(T->isIntegralType(Context) && "Integral type required!"); unsigned BitWidth = Context.getIntWidth(T); if (Value.isUnsigned() || Value.isNonNegative()) { if (T->isSignedIntegerOrEnumerationType()) --BitWidth; return Value.getActiveBits() <= BitWidth; } return Value.getMinSignedBits() <= BitWidth; } // \brief Given an integral type, return the next larger integral type // (or a NULL type of no such type exists). static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) { // FIXME: Int128/UInt128 support, which also needs to be introduced into // enum checking below. assert(T->isIntegralType(Context) && "Integral type required!"); const unsigned NumTypes = 4; QualType SignedIntegralTypes[NumTypes] = { Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy }; QualType UnsignedIntegralTypes[NumTypes] = { Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy }; unsigned BitWidth = Context.getTypeSize(T); QualType *Types = T->isSignedIntegerOrEnumerationType()? SignedIntegralTypes : UnsignedIntegralTypes; for (unsigned I = 0; I != NumTypes; ++I) if (Context.getTypeSize(Types[I]) > BitWidth) return Types[I]; return QualType(); } EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, Expr *Val) { unsigned IntWidth = Context.getTargetInfo().getIntWidth(); llvm::APSInt EnumVal(IntWidth); QualType EltTy; if (Val && DiagnoseUnexpandedParameterPack(Val, UPPC_EnumeratorValue)) Val = nullptr; if (Val) Val = DefaultLvalueConversion(Val).get(); if (Val) { if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; else { SourceLocation ExpLoc; if (getLangOpts().CPlusPlus11 && Enum->isFixed() && !getLangOpts().MSVCCompat) { // C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the // constant-expression in the enumerator-definition shall be a converted // constant expression of the underlying type. EltTy = Enum->getIntegerType(); ExprResult Converted = CheckConvertedConstantExpression(Val, EltTy, EnumVal, CCEK_Enumerator); if (Converted.isInvalid()) Val = nullptr; else Val = Converted.get(); } else if (!Val->isValueDependent() && !(Val = VerifyIntegerConstantExpression(Val, &EnumVal).get())) { // C99 6.7.2.2p2: Make sure we have an integer constant expression. } else { if (Enum->isFixed()) { EltTy = Enum->getIntegerType(); // In Obj-C and Microsoft mode, require the enumeration value to be // representable in the underlying type of the enumeration. In C++11, // we perform a non-narrowing conversion as part of converted constant // expression checking. if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { if (getLangOpts().MSVCCompat) { Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get(); } else Diag(IdLoc, diag::err_enumerator_too_large) << EltTy; } else Val = ImpCastExprToType(Val, EltTy, EltTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast) .get(); } else if (getLangOpts().CPlusPlus) { // C++11 [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: // - If an initializer is specified for an enumerator, the // initializing value has the same type as the expression. EltTy = Val->getType(); } else { // C99 6.7.2.2p2: // The expression that defines the value of an enumeration constant // shall be an integer constant expression that has a value // representable as an int. // Complain if the value is not representable in an int. if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) Diag(IdLoc, diag::ext_enum_value_not_int) << EnumVal.toString(10) << Val->getSourceRange() << (EnumVal.isUnsigned() || EnumVal.isNonNegative()); else if (!Context.hasSameType(Val->getType(), Context.IntTy)) { // Force the type of the expression to 'int'. Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).get(); } EltTy = Val->getType(); } } } } if (!Val) { if (Enum->isDependentType()) EltTy = Context.DependentTy; else if (!LastEnumConst) { // C++0x [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: // - If no initializer is specified for the first enumerator, the // initializing value has an unspecified integral type. // // GCC uses 'int' for its unspecified integral type, as does // C99 6.7.2.2p3. if (Enum->isFixed()) { EltTy = Enum->getIntegerType(); } else { EltTy = Context.IntTy; } } else { // Assign the last value + 1. EnumVal = LastEnumConst->getInitVal(); ++EnumVal; EltTy = LastEnumConst->getType(); // Check for overflow on increment. if (EnumVal < LastEnumConst->getInitVal()) { // C++0x [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: // // - Otherwise the type of the initializing value is the same as // the type of the initializing value of the preceding enumerator // unless the incremented value is not representable in that type, // in which case the type is an unspecified integral type // sufficient to contain the incremented value. If no such type // exists, the program is ill-formed. QualType T = getNextLargerIntegralType(Context, EltTy); if (T.isNull() || Enum->isFixed()) { // There is no integral type larger enough to represent this // value. Complain, then allow the value to wrap around. EnumVal = LastEnumConst->getInitVal(); EnumVal = EnumVal.zext(EnumVal.getBitWidth() * 2); ++EnumVal; if (Enum->isFixed()) // When the underlying type is fixed, this is ill-formed. Diag(IdLoc, diag::err_enumerator_wrapped) << EnumVal.toString(10) << EltTy; else Diag(IdLoc, diag::ext_enumerator_increment_too_large) << EnumVal.toString(10); } else { EltTy = T; } // Retrieve the last enumerator's value, extent that type to the // type that is supposed to be large enough to represent the incremented // value, then increment. EnumVal = LastEnumConst->getInitVal(); EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); ++EnumVal; // If we're not in C++, diagnose the overflow of enumerator values, // which in C99 means that the enumerator value is not representable in // an int (C99 6.7.2.2p2). However, we support GCC's extension that // permits enumerator values that are representable in some larger // integral type. if (!getLangOpts().CPlusPlus && !T.isNull()) Diag(IdLoc, diag::warn_enum_value_overflow); } else if (!getLangOpts().CPlusPlus && !isRepresentableIntegerValue(Context, EnumVal, EltTy)) { // Enforce C99 6.7.2.2p2 even when we compute the next value. Diag(IdLoc, diag::ext_enum_value_not_int) << EnumVal.toString(10) << 1; } } } if (!EltTy->isDependentType()) { // Make the enumerator value match the signedness and size of the // enumerator's type. EnumVal = EnumVal.extOrTrunc(Context.getIntWidth(EltTy)); EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); } return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, Val, EnumVal); } Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, SourceLocation IILoc) { if (!(getLangOpts().Modules || getLangOpts().ModulesLocalVisibility) || !getLangOpts().CPlusPlus) return SkipBodyInfo(); // We have an anonymous enum definition. Look up the first enumerator to // determine if we should merge the definition with an existing one and // skip the body. NamedDecl *PrevDecl = LookupSingleName(S, II, IILoc, LookupOrdinaryName, ForRedeclaration); auto *PrevECD = dyn_cast_or_null(PrevDecl); if (!PrevECD) return SkipBodyInfo(); EnumDecl *PrevED = cast(PrevECD->getDeclContext()); NamedDecl *Hidden; if (!PrevED->getDeclName() && !hasVisibleDefinition(PrevED, &Hidden)) { SkipBodyInfo Skip; Skip.Previous = Hidden; return Skip; } return SkipBodyInfo(); } Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, AttributeList *Attr, SourceLocation EqualLoc, Expr *Val) { EnumDecl *TheEnumDecl = cast(theEnumDecl); EnumConstantDecl *LastEnumConst = cast_or_null(lastEnumConst); // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. S = getNonFieldDeclScope(S); // Verify that there isn't already something declared with this name in this // scope. NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName, ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); // Just pretend that we didn't see the previous declaration. PrevDecl = nullptr; } // C++ [class.mem]p15: // If T is the name of a class, then each of the following shall have a name // different from T: // - every enumerator of every member of class T that is an unscoped // enumerated type if (!TheEnumDecl->isScoped()) DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(), DeclarationNameInfo(Id, IdLoc)); EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); if (!New) return nullptr; if (PrevDecl) { // When in C++, we may get a TagDecl with the same name; in this case the // enum constant will 'hide' the tag. assert((getLangOpts().CPlusPlus || !isa(PrevDecl)) && "Received TagDecl when not in C++!"); if (!isa(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S) && shouldLinkPossiblyHiddenDecl(PrevDecl, New)) { if (isa(PrevDecl)) Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; else Diag(IdLoc, diag::err_redefinition) << Id; notePreviousDefinition(PrevDecl->getLocation(), IdLoc); return nullptr; } } // Process attributes. if (Attr) ProcessDeclAttributeList(S, New, Attr); AddPragmaAttributes(S, New); // Register this decl in the current scope stack. New->setAccess(TheEnumDecl->getAccess()); PushOnScopeChains(New, S); ActOnDocumentableDecl(New); return New; } // Returns true when the enum initial expression does not trigger the // duplicate enum warning. A few common cases are exempted as follows: // Element2 = Element1 // Element2 = Element1 + 1 // Element2 = Element1 - 1 // Where Element2 and Element1 are from the same enum. static bool ValidDuplicateEnum(EnumConstantDecl *ECD, EnumDecl *Enum) { Expr *InitExpr = ECD->getInitExpr(); if (!InitExpr) return true; InitExpr = InitExpr->IgnoreImpCasts(); if (BinaryOperator *BO = dyn_cast(InitExpr)) { if (!BO->isAdditiveOp()) return true; IntegerLiteral *IL = dyn_cast(BO->getRHS()); if (!IL) return true; if (IL->getValue() != 1) return true; InitExpr = BO->getLHS(); } // This checks if the elements are from the same enum. DeclRefExpr *DRE = dyn_cast(InitExpr); if (!DRE) return true; EnumConstantDecl *EnumConstant = dyn_cast(DRE->getDecl()); if (!EnumConstant) return true; if (cast(TagDecl::castFromDeclContext(ECD->getDeclContext())) != Enum) return true; return false; } namespace { struct DupKey { int64_t val; bool isTombstoneOrEmptyKey; DupKey(int64_t val, bool isTombstoneOrEmptyKey) : val(val), isTombstoneOrEmptyKey(isTombstoneOrEmptyKey) {} }; static DupKey GetDupKey(const llvm::APSInt& Val) { return DupKey(Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue(), false); } struct DenseMapInfoDupKey { static DupKey getEmptyKey() { return DupKey(0, true); } static DupKey getTombstoneKey() { return DupKey(1, true); } static unsigned getHashValue(const DupKey Key) { return (unsigned)(Key.val * 37); } static bool isEqual(const DupKey& LHS, const DupKey& RHS) { return LHS.isTombstoneOrEmptyKey == RHS.isTombstoneOrEmptyKey && LHS.val == RHS.val; } }; } // end anonymous namespace // Emits a warning when an element is implicitly set a value that // a previous element has already been set to. static void CheckForDuplicateEnumValues(Sema &S, ArrayRef Elements, EnumDecl *Enum, QualType EnumType) { if (S.Diags.isIgnored(diag::warn_duplicate_enum_values, Enum->getLocation())) return; // Avoid anonymous enums if (!Enum->getIdentifier()) return; // Only check for small enums. if (Enum->getNumPositiveBits() > 63 || Enum->getNumNegativeBits() > 64) return; typedef SmallVector ECDVector; typedef SmallVector DuplicatesVector; typedef llvm::PointerUnion DeclOrVector; typedef llvm::DenseMap ValueToVectorMap; DuplicatesVector DupVector; ValueToVectorMap EnumMap; // Populate the EnumMap with all values represented by enum constants without // an initialier. for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null(Elements[i]); // Null EnumConstantDecl means a previous diagnostic has been emitted for // this constant. Skip this enum since it may be ill-formed. if (!ECD) { return; } if (ECD->getInitExpr()) continue; DupKey Key = GetDupKey(ECD->getInitVal()); DeclOrVector &Entry = EnumMap[Key]; // First time encountering this value. if (Entry.isNull()) Entry = ECD; } // Create vectors for any values that has duplicates. for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast(Elements[i]); if (!ValidDuplicateEnum(ECD, Enum)) continue; DupKey Key = GetDupKey(ECD->getInitVal()); DeclOrVector& Entry = EnumMap[Key]; if (Entry.isNull()) continue; if (EnumConstantDecl *D = Entry.dyn_cast()) { // Ensure constants are different. if (D == ECD) continue; // Create new vector and push values onto it. ECDVector *Vec = new ECDVector(); Vec->push_back(D); Vec->push_back(ECD); // Update entry to point to the duplicates vector. Entry = Vec; // Store the vector somewhere we can consult later for quick emission of // diagnostics. DupVector.push_back(Vec); continue; } ECDVector *Vec = Entry.get(); // Make sure constants are not added more than once. if (*Vec->begin() == ECD) continue; Vec->push_back(ECD); } // Emit diagnostics. for (DuplicatesVector::iterator DupVectorIter = DupVector.begin(), DupVectorEnd = DupVector.end(); DupVectorIter != DupVectorEnd; ++DupVectorIter) { ECDVector *Vec = *DupVectorIter; assert(Vec->size() > 1 && "ECDVector should have at least 2 elements."); // Emit warning for one enum constant. ECDVector::iterator I = Vec->begin(); S.Diag((*I)->getLocation(), diag::warn_duplicate_enum_values) << (*I)->getName() << (*I)->getInitVal().toString(10) << (*I)->getSourceRange(); ++I; // Emit one note for each of the remaining enum constants with // the same value. for (ECDVector::iterator E = Vec->end(); I != E; ++I) S.Diag((*I)->getLocation(), diag::note_duplicate_element) << (*I)->getName() << (*I)->getInitVal().toString(10) << (*I)->getSourceRange(); delete Vec; } } bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, bool AllowMask) const { assert(ED->isClosedFlag() && "looking for value in non-flag or open enum"); assert(ED->isCompleteDefinition() && "expected enum definition"); auto R = FlagBitsCache.insert(std::make_pair(ED, llvm::APInt())); llvm::APInt &FlagBits = R.first->second; if (R.second) { for (auto *E : ED->enumerators()) { const auto &EVal = E->getInitVal(); // Only single-bit enumerators introduce new flag values. if (EVal.isPowerOf2()) FlagBits = FlagBits.zextOrSelf(EVal.getBitWidth()) | EVal; } } // A value is in a flag enum if either its bits are a subset of the enum's // flag bits (the first condition) or we are allowing masks and the same is // true of its complement (the second condition). When masks are allowed, we // allow the common idiom of ~(enum1 | enum2) to be a valid enum value. // // While it's true that any value could be used as a mask, the assumption is // that a mask will have all of the insignificant bits set. Anything else is // likely a logic error. llvm::APInt FlagMask = ~FlagBits.zextOrTrunc(Val.getBitWidth()); return !(FlagMask & Val) || (AllowMask && !(FlagMask & ~Val)); } void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, Decl *EnumDeclX, ArrayRef Elements, Scope *S, AttributeList *Attr) { EnumDecl *Enum = cast(EnumDeclX); QualType EnumType = Context.getTypeDeclType(Enum); if (Attr) ProcessDeclAttributeList(S, Enum, Attr); if (Enum->isDependentType()) { for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null(Elements[i]); if (!ECD) continue; ECD->setType(EnumType); } Enum->completeDefinition(Context.DependentTy, Context.DependentTy, 0, 0); return; } // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. unsigned IntWidth = Context.getTargetInfo().getIntWidth(); unsigned CharWidth = Context.getTargetInfo().getCharWidth(); unsigned ShortWidth = Context.getTargetInfo().getShortWidth(); // Verify that all the values are okay, compute the size of the values, and // reverse the list. unsigned NumNegativeBits = 0; unsigned NumPositiveBits = 0; // Keep track of whether all elements have type int. bool AllElementsInt = true; for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. const llvm::APSInt &InitVal = ECD->getInitVal(); // Keep track of the size of positive and negative values. if (InitVal.isUnsigned() || InitVal.isNonNegative()) NumPositiveBits = std::max(NumPositiveBits, (unsigned)InitVal.getActiveBits()); else NumNegativeBits = std::max(NumNegativeBits, (unsigned)InitVal.getMinSignedBits()); // Keep track of whether every enum element has type int (very commmon). if (AllElementsInt) AllElementsInt = ECD->getType() == Context.IntTy; } // Figure out the type that should be used for this enum. QualType BestType; unsigned BestWidth; // C++0x N3000 [conv.prom]p3: // An rvalue of an unscoped enumeration type whose underlying // type is not fixed can be converted to an rvalue of the first // of the following types that can represent all the values of // the enumeration: int, unsigned int, long int, unsigned long // int, long long int, or unsigned long long int. // C99 6.4.4.3p2: // An identifier declared as an enumeration constant has type int. // The C99 rule is modified by a gcc extension QualType BestPromotionType; bool Packed = Enum->hasAttr(); // -fshort-enums is the equivalent to specifying the packed attribute on all // enum definitions. if (LangOpts.ShortEnums) Packed = true; if (Enum->isFixed()) { BestType = Enum->getIntegerType(); if (BestType->isPromotableIntegerType()) BestPromotionType = Context.getPromotedIntegerType(BestType); else BestPromotionType = BestType; BestWidth = Context.getIntWidth(BestType); } else if (NumNegativeBits) { // If there is a negative value, figure out the smallest integer type (of // int/long/longlong) that fits. // If it's packed, check also if it fits a char or a short. if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) { BestType = Context.SignedCharTy; BestWidth = CharWidth; } else if (Packed && NumNegativeBits <= ShortWidth && NumPositiveBits < ShortWidth) { BestType = Context.ShortTy; BestWidth = ShortWidth; } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { BestType = Context.IntTy; BestWidth = IntWidth; } else { BestWidth = Context.getTargetInfo().getLongWidth(); if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) { BestType = Context.LongTy; } else { BestWidth = Context.getTargetInfo().getLongLongWidth(); if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) Diag(Enum->getLocation(), diag::ext_enum_too_large); BestType = Context.LongLongTy; } } BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType); } else { // If there is no negative value, figure out the smallest type that fits // all of the enumerator values. // If it's packed, check also if it fits a char or a short. if (Packed && NumPositiveBits <= CharWidth) { BestType = Context.UnsignedCharTy; BestPromotionType = Context.IntTy; BestWidth = CharWidth; } else if (Packed && NumPositiveBits <= ShortWidth) { BestType = Context.UnsignedShortTy; BestPromotionType = Context.IntTy; BestWidth = ShortWidth; } else if (NumPositiveBits <= IntWidth) { BestType = Context.UnsignedIntTy; BestWidth = IntWidth; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus) ? Context.UnsignedIntTy : Context.IntTy; } else if (NumPositiveBits <= (BestWidth = Context.getTargetInfo().getLongWidth())) { BestType = Context.UnsignedLongTy; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus) ? Context.UnsignedLongTy : Context.LongTy; } else { BestWidth = Context.getTargetInfo().getLongLongWidth(); assert(NumPositiveBits <= BestWidth && "How could an initializer get larger than ULL?"); BestType = Context.UnsignedLongLongTy; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus) ? Context.UnsignedLongLongTy : Context.LongLongTy; } } // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. for (auto *D : Elements) { auto *ECD = cast_or_null(D); if (!ECD) continue; // Already issued a diagnostic. // Standard C says the enumerators have int type, but we allow, as an // extension, the enumerators to be larger than int size. If each // enumerator value fits in an int, type it as an int, otherwise type it the // same as the enumerator decl itself. This means that in "enum { X = 1U }" // that X has type 'int', not 'unsigned'. // Determine whether the value fits into an int. llvm::APSInt InitVal = ECD->getInitVal(); // If it fits into an integer type, force it. Otherwise force it to match // the enum decl type. QualType NewTy; unsigned NewWidth; bool NewSign; if (!getLangOpts().CPlusPlus && !Enum->isFixed() && isRepresentableIntegerValue(Context, InitVal, Context.IntTy)) { NewTy = Context.IntTy; NewWidth = IntWidth; NewSign = true; } else if (ECD->getType() == BestType) { // Already the right type! if (getLangOpts().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an // enum-specifier, each enumerator has the type of its // enumeration. ECD->setType(EnumType); continue; } else { NewTy = BestType; NewWidth = BestWidth; NewSign = BestType->isSignedIntegerOrEnumerationType(); } // Adjust the APSInt value. InitVal = InitVal.extOrTrunc(NewWidth); InitVal.setIsSigned(NewSign); ECD->setInitVal(InitVal); // Adjust the Expr initializer and type. if (ECD->getInitExpr() && !Context.hasSameType(NewTy, ECD->getInitExpr()->getType())) ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy, CK_IntegralCast, ECD->getInitExpr(), /*base paths*/ nullptr, VK_RValue)); if (getLangOpts().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an // enum-specifier, each enumerator has the type of its // enumeration. ECD->setType(EnumType); else ECD->setType(NewTy); } Enum->completeDefinition(BestType, BestPromotionType, NumPositiveBits, NumNegativeBits); CheckForDuplicateEnumValues(*this, Elements, Enum, EnumType); if (Enum->isClosedFlag()) { for (Decl *D : Elements) { EnumConstantDecl *ECD = cast_or_null(D); if (!ECD) continue; // Already issued a diagnostic. llvm::APSInt InitVal = ECD->getInitVal(); if (InitVal != 0 && !InitVal.isPowerOf2() && !IsValueInFlagEnum(Enum, InitVal, true)) Diag(ECD->getLocation(), diag::warn_flag_enum_constant_out_of_range) << ECD << Enum; } } // Now that the enum type is defined, ensure it's not been underaligned. if (Enum->hasAttrs()) CheckAlignasUnderalignment(Enum); } Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, SourceLocation StartLoc, SourceLocation EndLoc) { StringLiteral *AsmString = cast(expr); FileScopeAsmDecl *New = FileScopeAsmDecl::Create(Context, CurContext, AsmString, StartLoc, EndLoc); CurContext->addDecl(New); return New; } static void checkModuleImportContext(Sema &S, Module *M, SourceLocation ImportLoc, DeclContext *DC, bool FromInclude = false) { SourceLocation ExternCLoc; if (auto *LSD = dyn_cast(DC)) { switch (LSD->getLanguage()) { case LinkageSpecDecl::lang_c: if (ExternCLoc.isInvalid()) ExternCLoc = LSD->getLocStart(); break; case LinkageSpecDecl::lang_cxx: break; } DC = LSD->getParent(); } while (isa(DC)) DC = DC->getParent(); if (!isa(DC)) { S.Diag(ImportLoc, (FromInclude && S.isModuleVisible(M)) ? diag::ext_module_import_not_at_top_level_noop : diag::err_module_import_not_at_top_level_fatal) << M->getFullModuleName() << DC; S.Diag(cast(DC)->getLocStart(), diag::note_module_import_not_at_top_level) << DC; } else if (!M->IsExternC && ExternCLoc.isValid()) { S.Diag(ImportLoc, diag::ext_module_import_in_extern_c) << M->getFullModuleName(); S.Diag(ExternCLoc, diag::note_extern_c_begins_here); } } Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path) { // A module implementation unit requires that we are not compiling a module // of any kind. A module interface unit requires that we are not compiling a // module map. switch (getLangOpts().getCompilingModule()) { case LangOptions::CMK_None: // It's OK to compile a module interface as a normal translation unit. break; case LangOptions::CMK_ModuleInterface: if (MDK != ModuleDeclKind::Implementation) break; // We were asked to compile a module interface unit but this is a module // implementation unit. That indicates the 'export' is missing. Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch) << FixItHint::CreateInsertion(ModuleLoc, "export "); break; case LangOptions::CMK_ModuleMap: Diag(ModuleLoc, diag::err_module_decl_in_module_map_module); return nullptr; } // FIXME: Create a ModuleDecl and return it. // FIXME: Most of this work should be done by the preprocessor rather than // here, in order to support macro import. // Flatten the dots in a module name. Unlike Clang's hierarchical module map // modules, the dots here are just another character that can appear in a // module name. std::string ModuleName; for (auto &Piece : Path) { if (!ModuleName.empty()) ModuleName += "."; ModuleName += Piece.first->getName(); } // If a module name was explicitly specified on the command line, it must be // correct. if (!getLangOpts().CurrentModule.empty() && getLangOpts().CurrentModule != ModuleName) { Diag(Path.front().second, diag::err_current_module_name_mismatch) << SourceRange(Path.front().second, Path.back().second) << getLangOpts().CurrentModule; return nullptr; } const_cast(getLangOpts()).CurrentModule = ModuleName; auto &Map = PP.getHeaderSearchInfo().getModuleMap(); switch (MDK) { case ModuleDeclKind::Module: { // FIXME: Check we're not in a submodule. // We can't have parsed or imported a definition of this module or parsed a // module map defining it already. if (auto *M = Map.findModule(ModuleName)) { Diag(Path[0].second, diag::err_module_redefinition) << ModuleName; if (M->DefinitionLoc.isValid()) Diag(M->DefinitionLoc, diag::note_prev_module_definition); else if (const auto *FE = M->getASTFile()) Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) << FE->getName(); return nullptr; } // Create a Module for the module that we're defining. Module *Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); assert(Mod && "module creation should not fail"); // Enter the semantic scope of the module. ActOnModuleBegin(ModuleLoc, Mod); return nullptr; } case ModuleDeclKind::Partition: // FIXME: Check we are in a submodule of the named module. return nullptr; case ModuleDeclKind::Implementation: std::pair ModuleNameLoc( PP.getIdentifierInfo(ModuleName), Path[0].second); DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, ModuleNameLoc); if (Import.isInvalid()) return nullptr; return ConvertDeclToDeclGroup(Import.get()); } llvm_unreachable("unexpected module decl kind"); } DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, SourceLocation ImportLoc, ModuleIdPath Path) { Module *Mod = getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, /*IsIncludeDirective=*/false); if (!Mod) return true; VisibleModules.setVisible(Mod, ImportLoc); checkModuleImportContext(*this, Mod, ImportLoc, CurContext); // FIXME: we should support importing a submodule within a different submodule // of the same top-level module. Until we do, make it an error rather than // silently ignoring the import. // Import-from-implementation is valid in the Modules TS. FIXME: Should we // warn on a redundant import of the current module? if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) Diag(ImportLoc, getLangOpts().isCompilingModule() ? diag::err_module_self_import : diag::err_module_import_in_implementation) << Mod->getFullModuleName() << getLangOpts().CurrentModule; SmallVector IdentifierLocs; Module *ModCheck = Mod; for (unsigned I = 0, N = Path.size(); I != N; ++I) { // If we've run out of module parents, just drop the remaining identifiers. // We need the length to be consistent. if (!ModCheck) break; ModCheck = ModCheck->Parent; IdentifierLocs.push_back(Path[I].second); } TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); ImportDecl *Import = ImportDecl::Create(Context, TU, StartLoc, Mod, IdentifierLocs); if (!ModuleScopes.empty()) Context.addModuleInitializer(ModuleScopes.back().Module, Import); TU->addDecl(Import); return Import; } void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); BuildModuleInclude(DirectiveLoc, Mod); } void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { // Determine whether we're in the #include buffer for a module. The #includes // in that buffer do not qualify as module imports; they're just an // implementation detail of us building the module. // // FIXME: Should we even get ActOnModuleInclude calls for those? bool IsInModuleIncludes = TUKind == TU_Module && getSourceManager().isWrittenInMainFile(DirectiveLoc); bool ShouldAddImport = !IsInModuleIncludes; // If this module import was due to an inclusion directive, create an // implicit import declaration to capture it in the AST. if (ShouldAddImport) { TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, DirectiveLoc, Mod, DirectiveLoc); if (!ModuleScopes.empty()) Context.addModuleInitializer(ModuleScopes.back().Module, ImportD); TU->addDecl(ImportD); Consumer.HandleImplicitImportDecl(ImportD); } getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc); VisibleModules.setVisible(Mod, DirectiveLoc); } void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); ModuleScopes.push_back({}); ModuleScopes.back().Module = Mod; if (getLangOpts().ModulesLocalVisibility) ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); VisibleModules.setVisible(Mod, DirectiveLoc); + + // The enclosing context is now part of this module. + // FIXME: Consider creating a child DeclContext to hold the entities + // lexically within the module. + if (getLangOpts().trackLocalOwningModule()) { + cast(CurContext)->setHidden(true); + cast(CurContext)->setLocalOwningModule(Mod); + } } void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) { if (getLangOpts().ModulesLocalVisibility) { VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules); // Leaving a module hides namespace names, so our visible namespace cache // is now out of date. VisibleNamespaceCache.clear(); } assert(!ModuleScopes.empty() && ModuleScopes.back().Module == Mod && "left the wrong module scope"); ModuleScopes.pop_back(); // We got to the end of processing a local module. Create an // ImportDecl as we would for an imported module. FileID File = getSourceManager().getFileID(EomLoc); SourceLocation DirectiveLoc; if (EomLoc == getSourceManager().getLocForEndOfFile(File)) { // We reached the end of a #included module header. Use the #include loc. assert(File != getSourceManager().getMainFileID() && "end of submodule in main source file"); DirectiveLoc = getSourceManager().getIncludeLoc(File); } else { // We reached an EOM pragma. Use the pragma location. DirectiveLoc = EomLoc; } BuildModuleInclude(DirectiveLoc, Mod); + + // Any further declarations are in whatever module we returned to. + if (getLangOpts().trackLocalOwningModule()) { + cast(CurContext)->setLocalOwningModule(getCurrentModule()); + if (!getCurrentModule()) + cast(CurContext)->setHidden(false); + } } void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod) { // Bail if we're not allowed to implicitly import a module here. if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery) return; // Create the implicit import declaration. TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, Loc, Mod, Loc); TU->addDecl(ImportD); Consumer.HandleImplicitImportDecl(ImportD); // Make the module visible. getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc); VisibleModules.setVisible(Mod, Loc); } /// We have parsed the start of an export declaration, including the '{' /// (if present). Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, SourceLocation LBraceLoc) { ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc); // C++ Modules TS draft: // An export-declaration shall appear in the purview of a module other than // the global module. if (ModuleScopes.empty() || !ModuleScopes.back().Module || ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) Diag(ExportLoc, diag::err_export_not_in_module_interface); // An export-declaration [...] shall not contain more than one // export keyword. // // The intent here is that an export-declaration cannot appear within another // export-declaration. if (D->isExported()) Diag(ExportLoc, diag::err_export_within_export); CurContext->addDecl(D); PushDeclContext(S, D); return D; } /// Complete the definition of an export declaration. Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) { auto *ED = cast(D); if (RBraceLoc.isValid()) ED->setRBraceLoc(RBraceLoc); // FIXME: Diagnose export of internal-linkage declaration (including // anonymous namespace). PopDeclContext(); return D; } void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { NamedDecl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), AliasNameLoc); // If a declaration that: // 1) declares a function or a variable // 2) has external linkage // already exists, add a label attribute to it. if (PrevDecl && (isa(PrevDecl) || isa(PrevDecl))) { if (isDeclExternC(PrevDecl)) PrevDecl->addAttr(Attr); else Diag(PrevDecl->getLocation(), diag::warn_redefine_extname_not_applied) << /*Variable*/(isa(PrevDecl) ? 0 : 1) << PrevDecl; // Otherwise, add a label atttibute to ExtnameUndeclaredIdentifiers. } else (void)ExtnameUndeclaredIdentifiers.insert(std::make_pair(Name, Attr)); } void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); if (PrevDecl) { PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc)); } else { (void)WeakUndeclaredIdentifiers.insert( std::pair (Name, WeakInfo((IdentifierInfo*)nullptr, NameLoc))); } } void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { Decl *PrevDecl = LookupSingleName(TUScope, AliasName, AliasNameLoc, LookupOrdinaryName); WeakInfo W = WeakInfo(Name, NameLoc); if (PrevDecl && (isa(PrevDecl) || isa(PrevDecl))) { if (!PrevDecl->hasAttr()) if (NamedDecl *ND = dyn_cast(PrevDecl)) DeclApplyPragmaWeak(TUScope, ND, W); } else { (void)WeakUndeclaredIdentifiers.insert( std::pair(AliasName, W)); } } Decl *Sema::getObjCDeclContext() const { return (dyn_cast_or_null(CurContext)); } Index: vendor/clang/dist/lib/Sema/SemaLookup.cpp =================================================================== --- vendor/clang/dist/lib/Sema/SemaLookup.cpp (revision 318415) +++ vendor/clang/dist/lib/Sema/SemaLookup.cpp (revision 318416) @@ -1,5147 +1,5090 @@ //===--------------------- SemaLookup.cpp - Name Lookup ------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements name lookup for C, C++, Objective-C, and // Objective-C++. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclLookups.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/edit_distance.h" #include "llvm/Support/ErrorHandling.h" #include #include #include #include #include #include using namespace clang; using namespace sema; namespace { class UnqualUsingEntry { const DeclContext *Nominated; const DeclContext *CommonAncestor; public: UnqualUsingEntry(const DeclContext *Nominated, const DeclContext *CommonAncestor) : Nominated(Nominated), CommonAncestor(CommonAncestor) { } const DeclContext *getCommonAncestor() const { return CommonAncestor; } const DeclContext *getNominatedNamespace() const { return Nominated; } // Sort by the pointer value of the common ancestor. struct Comparator { bool operator()(const UnqualUsingEntry &L, const UnqualUsingEntry &R) { return L.getCommonAncestor() < R.getCommonAncestor(); } bool operator()(const UnqualUsingEntry &E, const DeclContext *DC) { return E.getCommonAncestor() < DC; } bool operator()(const DeclContext *DC, const UnqualUsingEntry &E) { return DC < E.getCommonAncestor(); } }; }; /// A collection of using directives, as used by C++ unqualified /// lookup. class UnqualUsingDirectiveSet { typedef SmallVector ListTy; ListTy list; llvm::SmallPtrSet visited; public: UnqualUsingDirectiveSet() {} void visitScopeChain(Scope *S, Scope *InnermostFileScope) { // C++ [namespace.udir]p1: // During unqualified name lookup, the names appear as if they // were declared in the nearest enclosing namespace which contains // both the using-directive and the nominated namespace. DeclContext *InnermostFileDC = InnermostFileScope->getEntity(); assert(InnermostFileDC && InnermostFileDC->isFileContext()); for (; S; S = S->getParent()) { // C++ [namespace.udir]p1: // A using-directive shall not appear in class scope, but may // appear in namespace scope or in block scope. DeclContext *Ctx = S->getEntity(); if (Ctx && Ctx->isFileContext()) { visit(Ctx, Ctx); } else if (!Ctx || Ctx->isFunctionOrMethod()) { for (auto *I : S->using_directives()) visit(I, InnermostFileDC); } } } // Visits a context and collect all of its using directives // recursively. Treats all using directives as if they were // declared in the context. // // A given context is only every visited once, so it is important // that contexts be visited from the inside out in order to get // the effective DCs right. void visit(DeclContext *DC, DeclContext *EffectiveDC) { if (!visited.insert(DC).second) return; addUsingDirectives(DC, EffectiveDC); } // Visits a using directive and collects all of its using // directives recursively. Treats all using directives as if they // were declared in the effective DC. void visit(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) { DeclContext *NS = UD->getNominatedNamespace(); if (!visited.insert(NS).second) return; addUsingDirective(UD, EffectiveDC); addUsingDirectives(NS, EffectiveDC); } // Adds all the using directives in a context (and those nominated // by its using directives, transitively) as if they appeared in // the given effective context. void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) { SmallVector queue; while (true) { for (auto UD : DC->using_directives()) { DeclContext *NS = UD->getNominatedNamespace(); if (visited.insert(NS).second) { addUsingDirective(UD, EffectiveDC); queue.push_back(NS); } } if (queue.empty()) return; DC = queue.pop_back_val(); } } // Add a using directive as if it had been declared in the given // context. This helps implement C++ [namespace.udir]p3: // The using-directive is transitive: if a scope contains a // using-directive that nominates a second namespace that itself // contains using-directives, the effect is as if the // using-directives from the second namespace also appeared in // the first. void addUsingDirective(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) { // Find the common ancestor between the effective context and // the nominated namespace. DeclContext *Common = UD->getNominatedNamespace(); while (!Common->Encloses(EffectiveDC)) Common = Common->getParent(); Common = Common->getPrimaryContext(); list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common)); } void done() { std::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator()); } typedef ListTy::const_iterator const_iterator; const_iterator begin() const { return list.begin(); } const_iterator end() const { return list.end(); } llvm::iterator_range getNamespacesFor(DeclContext *DC) const { return llvm::make_range(std::equal_range(begin(), end(), DC->getPrimaryContext(), UnqualUsingEntry::Comparator())); } }; } // end anonymous namespace // Retrieve the set of identifier namespaces that correspond to a // specific kind of name lookup. static inline unsigned getIDNS(Sema::LookupNameKind NameKind, bool CPlusPlus, bool Redeclaration) { unsigned IDNS = 0; switch (NameKind) { case Sema::LookupObjCImplicitSelfParam: case Sema::LookupOrdinaryName: case Sema::LookupRedeclarationWithLinkage: case Sema::LookupLocalFriendName: IDNS = Decl::IDNS_Ordinary; if (CPlusPlus) { IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace; if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; } if (Redeclaration) IDNS |= Decl::IDNS_LocalExtern; break; case Sema::LookupOperatorName: // Operator lookup is its own crazy thing; it is not the same // as (e.g.) looking up an operator name for redeclaration. assert(!Redeclaration && "cannot do redeclaration operator lookup"); IDNS = Decl::IDNS_NonMemberOperator; break; case Sema::LookupTagName: if (CPlusPlus) { IDNS = Decl::IDNS_Type; // When looking for a redeclaration of a tag name, we add: // 1) TagFriend to find undeclared friend decls // 2) Namespace because they can't "overload" with tag decls. // 3) Tag because it includes class templates, which can't // "overload" with tag decls. if (Redeclaration) IDNS |= Decl::IDNS_Tag | Decl::IDNS_TagFriend | Decl::IDNS_Namespace; } else { IDNS = Decl::IDNS_Tag; } break; case Sema::LookupLabel: IDNS = Decl::IDNS_Label; break; case Sema::LookupMemberName: IDNS = Decl::IDNS_Member; if (CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary; break; case Sema::LookupNestedNameSpecifierName: IDNS = Decl::IDNS_Type | Decl::IDNS_Namespace; break; case Sema::LookupNamespaceName: IDNS = Decl::IDNS_Namespace; break; case Sema::LookupUsingDeclName: assert(Redeclaration && "should only be used for redecl lookup"); IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend | Decl::IDNS_LocalExtern; break; case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; case Sema::LookupOMPReductionName: IDNS = Decl::IDNS_OMPReduction; break; case Sema::LookupAnyName: IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol | Decl::IDNS_Type; break; } return IDNS; } void LookupResult::configure() { IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus, isForRedeclaration()); // If we're looking for one of the allocation or deallocation // operators, make sure that the implicitly-declared new and delete // operators can be found. switch (NameInfo.getName().getCXXOverloadedOperator()) { case OO_New: case OO_Delete: case OO_Array_New: case OO_Array_Delete: getSema().DeclareGlobalNewDelete(); break; default: break; } // Compiler builtins are always visible, regardless of where they end // up being declared. if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) { if (unsigned BuiltinID = Id->getBuiltinID()) { if (!getSema().Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) AllowHidden = true; } } } bool LookupResult::sanity() const { // This function is never called by NDEBUG builds. assert(ResultKind != NotFound || Decls.size() == 0); assert(ResultKind != Found || Decls.size() == 1); assert(ResultKind != FoundOverloaded || Decls.size() > 1 || (Decls.size() == 1 && isa((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); assert(ResultKind != Ambiguous || Decls.size() > 1 || (Decls.size() == 1 && (Ambiguity == AmbiguousBaseSubobjects || Ambiguity == AmbiguousBaseSubobjectTypes))); assert((Paths != nullptr) == (ResultKind == Ambiguous && (Ambiguity == AmbiguousBaseSubobjectTypes || Ambiguity == AmbiguousBaseSubobjects))); return true; } // Necessary because CXXBasePaths is not complete in Sema.h void LookupResult::deletePaths(CXXBasePaths *Paths) { delete Paths; } /// Get a representative context for a declaration such that two declarations /// will have the same context if they were found within the same scope. static DeclContext *getContextForScopeMatching(Decl *D) { // For function-local declarations, use that function as the context. This // doesn't account for scopes within the function; the caller must deal with // those. DeclContext *DC = D->getLexicalDeclContext(); if (DC->isFunctionOrMethod()) return DC; // Otherwise, look at the semantic context of the declaration. The // declaration must have been found there. return D->getDeclContext()->getRedeclContext(); } /// \brief Determine whether \p D is a better lookup result than \p Existing, /// given that they declare the same entity. static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, NamedDecl *D, NamedDecl *Existing) { // When looking up redeclarations of a using declaration, prefer a using // shadow declaration over any other declaration of the same entity. if (Kind == Sema::LookupUsingDeclName && isa(D) && !isa(Existing)) return true; auto *DUnderlying = D->getUnderlyingDecl(); auto *EUnderlying = Existing->getUnderlyingDecl(); // If they have different underlying declarations, prefer a typedef over the // original type (this happens when two type declarations denote the same // type), per a generous reading of C++ [dcl.typedef]p3 and p4. The typedef // might carry additional semantic information, such as an alignment override. // However, per C++ [dcl.typedef]p5, when looking up a tag name, prefer a tag // declaration over a typedef. if (DUnderlying->getCanonicalDecl() != EUnderlying->getCanonicalDecl()) { assert(isa(DUnderlying) && isa(EUnderlying)); bool HaveTag = isa(EUnderlying); bool WantTag = Kind == Sema::LookupTagName; return HaveTag != WantTag; } // Pick the function with more default arguments. // FIXME: In the presence of ambiguous default arguments, we should keep both, // so we can diagnose the ambiguity if the default argument is needed. // See C++ [over.match.best]p3. if (auto *DFD = dyn_cast(DUnderlying)) { auto *EFD = cast(EUnderlying); unsigned DMin = DFD->getMinRequiredArguments(); unsigned EMin = EFD->getMinRequiredArguments(); // If D has more default arguments, it is preferred. if (DMin != EMin) return DMin < EMin; // FIXME: When we track visibility for default function arguments, check // that we pick the declaration with more visible default arguments. } // Pick the template with more default template arguments. if (auto *DTD = dyn_cast(DUnderlying)) { auto *ETD = cast(EUnderlying); unsigned DMin = DTD->getTemplateParameters()->getMinRequiredArguments(); unsigned EMin = ETD->getTemplateParameters()->getMinRequiredArguments(); // If D has more default arguments, it is preferred. Note that default // arguments (and their visibility) is monotonically increasing across the // redeclaration chain, so this is a quick proxy for "is more recent". if (DMin != EMin) return DMin < EMin; // If D has more *visible* default arguments, it is preferred. Note, an // earlier default argument being visible does not imply that a later // default argument is visible, so we can't just check the first one. for (unsigned I = DMin, N = DTD->getTemplateParameters()->size(); I != N; ++I) { if (!S.hasVisibleDefaultArgument( ETD->getTemplateParameters()->getParam(I)) && S.hasVisibleDefaultArgument( DTD->getTemplateParameters()->getParam(I))) return true; } } // VarDecl can have incomplete array types, prefer the one with more complete // array type. if (VarDecl *DVD = dyn_cast(DUnderlying)) { VarDecl *EVD = cast(EUnderlying); if (EVD->getType()->isIncompleteType() && !DVD->getType()->isIncompleteType()) { // Prefer the decl with a more complete type if visible. return S.isVisible(DVD); } return false; // Avoid picking up a newer decl, just because it was newer. } // For most kinds of declaration, it doesn't really matter which one we pick. if (!isa(DUnderlying) && !isa(DUnderlying)) { // If the existing declaration is hidden, prefer the new one. Otherwise, // keep what we've got. return !S.isVisible(Existing); } // Pick the newer declaration; it might have a more precise type. for (Decl *Prev = DUnderlying->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) if (Prev == EUnderlying) return true; return false; } /// Determine whether \p D can hide a tag declaration. static bool canHideTag(NamedDecl *D) { // C++ [basic.scope.declarative]p4: // Given a set of declarations in a single declarative region [...] // exactly one declaration shall declare a class name or enumeration name // that is not a typedef name and the other declarations shall all refer to // the same variable, non-static data member, or enumerator, or all refer // to functions and function templates; in this case the class name or // enumeration name is hidden. // C++ [basic.scope.hiding]p2: // A class name or enumeration name can be hidden by the name of a // variable, data member, function, or enumerator declared in the same // scope. // An UnresolvedUsingValueDecl always instantiates to one of these. D = D->getUnderlyingDecl(); return isa(D) || isa(D) || isa(D) || isa(D) || isa(D) || isa(D); } /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); // Fast case: no possible ambiguity. if (N == 0) { assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation); return; } // If there's a single decl, we need to examine it to decide what // kind of lookup this is. if (N == 1) { NamedDecl *D = (*Decls.begin())->getUnderlyingDecl(); if (isa(D)) ResultKind = FoundOverloaded; else if (isa(D)) ResultKind = FoundUnresolvedValue; return; } // Don't do any extra resolution if we've already resolved as ambiguous. if (ResultKind == Ambiguous) return; llvm::SmallDenseMap Unique; llvm::SmallDenseMap UniqueTypes; bool Ambiguous = false; bool HasTag = false, HasFunction = false; bool HasFunctionTemplate = false, HasUnresolved = false; NamedDecl *HasNonFunction = nullptr; llvm::SmallVector EquivalentNonFunctions; unsigned UniqueTagIndex = 0; unsigned I = 0; while (I < N) { NamedDecl *D = Decls[I]->getUnderlyingDecl(); D = cast(D->getCanonicalDecl()); // Ignore an invalid declaration unless it's the only one left. if (D->isInvalidDecl() && !(I == 0 && N == 1)) { Decls[I] = Decls[--N]; continue; } llvm::Optional ExistingI; // Redeclarations of types via typedef can occur both within a scope // and, through using declarations and directives, across scopes. There is // no ambiguity if they all refer to the same type, so unique based on the // canonical type. if (TypeDecl *TD = dyn_cast(D)) { QualType T = getSema().Context.getTypeDeclType(TD); auto UniqueResult = UniqueTypes.insert( std::make_pair(getSema().Context.getCanonicalType(T), I)); if (!UniqueResult.second) { // The type is not unique. ExistingI = UniqueResult.first->second; } } // For non-type declarations, check for a prior lookup result naming this // canonical declaration. if (!ExistingI) { auto UniqueResult = Unique.insert(std::make_pair(D, I)); if (!UniqueResult.second) { // We've seen this entity before. ExistingI = UniqueResult.first->second; } } if (ExistingI) { // This is not a unique lookup result. Pick one of the results and // discard the other. if (isPreferredLookupResult(getSema(), getLookupKind(), Decls[I], Decls[*ExistingI])) Decls[*ExistingI] = Decls[I]; Decls[I] = Decls[--N]; continue; } // Otherwise, do some decl type analysis and then continue. if (isa(D)) { HasUnresolved = true; } else if (isa(D)) { if (HasTag) Ambiguous = true; UniqueTagIndex = I; HasTag = true; } else if (isa(D)) { HasFunction = true; HasFunctionTemplate = true; } else if (isa(D)) { HasFunction = true; } else { if (HasNonFunction) { // If we're about to create an ambiguity between two declarations that // are equivalent, but one is an internal linkage declaration from one // module and the other is an internal linkage declaration from another // module, just skip it. if (getSema().isEquivalentInternalLinkageDeclaration(HasNonFunction, D)) { EquivalentNonFunctions.push_back(D); Decls[I] = Decls[--N]; continue; } Ambiguous = true; } HasNonFunction = D; } I++; } // C++ [basic.scope.hiding]p2: // A class name or enumeration name can be hidden by the name of // an object, function, or enumerator declared in the same // scope. If a class or enumeration name and an object, function, // or enumerator are declared in the same scope (in any order) // with the same name, the class or enumeration name is hidden // wherever the object, function, or enumerator name is visible. // But it's still an error if there are distinct tag types found, // even if they're not visible. (ref?) if (N > 1 && HideTags && HasTag && !Ambiguous && (HasFunction || HasNonFunction || HasUnresolved)) { NamedDecl *OtherDecl = Decls[UniqueTagIndex ? 0 : N - 1]; if (isa(Decls[UniqueTagIndex]->getUnderlyingDecl()) && getContextForScopeMatching(Decls[UniqueTagIndex])->Equals( getContextForScopeMatching(OtherDecl)) && canHideTag(OtherDecl)) Decls[UniqueTagIndex] = Decls[--N]; else Ambiguous = true; } // FIXME: This diagnostic should really be delayed until we're done with // the lookup result, in case the ambiguity is resolved by the caller. if (!EquivalentNonFunctions.empty() && !Ambiguous) getSema().diagnoseEquivalentInternalLinkageDeclarations( getNameLoc(), HasNonFunction, EquivalentNonFunctions); Decls.set_size(N); if (HasNonFunction && (HasFunction || HasUnresolved)) Ambiguous = true; if (Ambiguous) setAmbiguous(LookupResult::AmbiguousReference); else if (HasUnresolved) ResultKind = LookupResult::FoundUnresolvedValue; else if (N > 1 || HasFunctionTemplate) ResultKind = LookupResult::FoundOverloaded; else ResultKind = LookupResult::Found; } void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { CXXBasePaths::const_paths_iterator I, E; for (I = P.begin(), E = P.end(); I != E; ++I) for (DeclContext::lookup_iterator DI = I->Decls.begin(), DE = I->Decls.end(); DI != DE; ++DI) addDecl(*DI); } void LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) { Paths = new CXXBasePaths; Paths->swap(P); addDeclsFromBasePaths(*Paths); resolveKind(); setAmbiguous(AmbiguousBaseSubobjects); } void LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) { Paths = new CXXBasePaths; Paths->swap(P); addDeclsFromBasePaths(*Paths); resolveKind(); setAmbiguous(AmbiguousBaseSubobjectTypes); } void LookupResult::print(raw_ostream &Out) { Out << Decls.size() << " result(s)"; if (isAmbiguous()) Out << ", ambiguous"; if (Paths) Out << ", base paths present"; for (iterator I = begin(), E = end(); I != E; ++I) { Out << "\n"; (*I)->print(Out, 2); } } LLVM_DUMP_METHOD void LookupResult::dump() { llvm::errs() << "lookup results for " << getLookupName().getAsString() << ":\n"; for (NamedDecl *D : *this) D->dump(); } /// \brief Lookup a builtin function, when name lookup would otherwise /// fail. static bool LookupBuiltin(Sema &S, LookupResult &R) { Sema::LookupNameKind NameKind = R.getLookupKind(); // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. if (NameKind == Sema::LookupOrdinaryName || NameKind == Sema::LookupRedeclarationWithLinkage) { IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo(); if (II) { if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) { if (II == S.getASTContext().getMakeIntegerSeqName()) { R.addDecl(S.getASTContext().getMakeIntegerSeqDecl()); return true; } else if (II == S.getASTContext().getTypePackElementName()) { R.addDecl(S.getASTContext().getTypePackElementDecl()); return true; } } // If this is a builtin on this (or all) targets, create the decl. if (unsigned BuiltinID = II->getBuiltinID()) { // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined // library functions like 'malloc'. Instead, we'll just error. if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) && S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, S.TUScope, R.isForRedeclaration(), R.getNameLoc())) { R.addDecl(D); return true; } } } } return false; } /// \brief Determine whether we can declare a special member function within /// the class at this point. static bool CanDeclareSpecialMemberFunction(const CXXRecordDecl *Class) { // We need to have a definition for the class. if (!Class->getDefinition() || Class->isDependentContext()) return false; // We can't be in the middle of defining the class. return !Class->isBeingDefined(); } void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { if (!CanDeclareSpecialMemberFunction(Class)) return; // If the default constructor has not yet been declared, do so now. if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); // If the copy constructor has not yet been declared, do so now. if (Class->needsImplicitCopyConstructor()) DeclareImplicitCopyConstructor(Class); // If the copy assignment operator has not yet been declared, do so now. if (Class->needsImplicitCopyAssignment()) DeclareImplicitCopyAssignment(Class); if (getLangOpts().CPlusPlus11) { // If the move constructor has not yet been declared, do so now. if (Class->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(Class); // If the move assignment operator has not yet been declared, do so now. if (Class->needsImplicitMoveAssignment()) DeclareImplicitMoveAssignment(Class); } // If the destructor has not yet been declared, do so now. if (Class->needsImplicitDestructor()) DeclareImplicitDestructor(Class); } /// \brief Determine whether this is the name of an implicitly-declared /// special member function. static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: return true; case DeclarationName::CXXOperatorName: return Name.getCXXOverloadedOperator() == OO_Equal; default: break; } return false; } /// \brief If there are any implicit member functions with the given name /// that need to be declared in the given declaration context, do so. static void DeclareImplicitMemberFunctionsWithName(Sema &S, DeclarationName Name, SourceLocation Loc, const DeclContext *DC) { if (!DC) return; switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && CanDeclareSpecialMemberFunction(Record)) { CXXRecordDecl *Class = const_cast(Record); if (Record->needsImplicitDefaultConstructor()) S.DeclareImplicitDefaultConstructor(Class); if (Record->needsImplicitCopyConstructor()) S.DeclareImplicitCopyConstructor(Class); if (S.getLangOpts().CPlusPlus11 && Record->needsImplicitMoveConstructor()) S.DeclareImplicitMoveConstructor(Class); } break; case DeclarationName::CXXDestructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && Record->needsImplicitDestructor() && CanDeclareSpecialMemberFunction(Record)) S.DeclareImplicitDestructor(const_cast(Record)); break; case DeclarationName::CXXOperatorName: if (Name.getCXXOverloadedOperator() != OO_Equal) break; if (const CXXRecordDecl *Record = dyn_cast(DC)) { if (Record->getDefinition() && CanDeclareSpecialMemberFunction(Record)) { CXXRecordDecl *Class = const_cast(Record); if (Record->needsImplicitCopyAssignment()) S.DeclareImplicitCopyAssignment(Class); if (S.getLangOpts().CPlusPlus11 && Record->needsImplicitMoveAssignment()) S.DeclareImplicitMoveAssignment(Class); } } break; case DeclarationName::CXXDeductionGuideName: S.DeclareImplicitDeductionGuides(Name.getCXXDeductionGuideTemplate(), Loc); break; default: break; } } // Adds all qualifying matches for a name within a decl context to the // given lookup result. Returns true if any matches were found. static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { bool Found = false; // Lazily declare C++ special member functions. if (S.getLangOpts().CPlusPlus) DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), R.getNameLoc(), DC); // Perform lookup into this declaration context. DeclContext::lookup_result DR = DC->lookup(R.getLookupName()); for (NamedDecl *D : DR) { if ((D = R.getAcceptableDecl(D))) { R.addDecl(D); Found = true; } } if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R)) return true; if (R.getLookupName().getNameKind() != DeclarationName::CXXConversionFunctionName || R.getLookupName().getCXXNameType()->isDependentType() || !isa(DC)) return Found; // C++ [temp.mem]p6: // A specialization of a conversion function template is not found by // name lookup. Instead, any conversion function templates visible in the // context of the use are considered. [...] const CXXRecordDecl *Record = cast(DC); if (!Record->isCompleteDefinition()) return Found; for (CXXRecordDecl::conversion_iterator U = Record->conversion_begin(), UEnd = Record->conversion_end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast(*U); if (!ConvTemplate) continue; // When we're performing lookup for the purposes of redeclaration, just // add the conversion function template. When we deduce template // arguments for specializations, we'll end up unifying the return // type of the new declaration with the type of the function template. if (R.isForRedeclaration()) { R.addDecl(ConvTemplate); Found = true; continue; } // C++ [temp.mem]p6: // [...] For each such operator, if argument deduction succeeds // (14.9.2.3), the resulting specialization is used as if found by // name lookup. // // When referencing a conversion function for any purpose other than // a redeclaration (such that we'll be building an expression with the // result), perform template argument deduction and place the // specialization into the result set. We do this to avoid forcing all // callers to perform special deduction for conversion functions. TemplateDeductionInfo Info(R.getNameLoc()); FunctionDecl *Specialization = nullptr; const FunctionProtoType *ConvProto = ConvTemplate->getTemplatedDecl()->getType()->getAs(); assert(ConvProto && "Nonsensical conversion function template type"); // Compute the type of the function that we would expect the conversion // function to have, if it were to match the name given. // FIXME: Calling convention! FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo(); EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C); EPI.ExceptionSpec = EST_None; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), None, EPI); // Perform template argument deduction against the type that we would // expect the function to have. if (R.getSema().DeduceTemplateArguments(ConvTemplate, nullptr, ExpectedType, Specialization, Info) == Sema::TDK_Success) { R.addDecl(Specialization); Found = true; } } return Found; } // Performs C++ unqualified lookup into the given file context. static bool CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, DeclContext *NS, UnqualUsingDirectiveSet &UDirs) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); // Perform direct name lookup into the LookupCtx. bool Found = LookupDirect(S, R, NS); // Perform direct name lookup into the namespaces nominated by the // using directives whose common ancestor is this namespace. for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(NS)) if (LookupDirect(S, R, UUE.getNominatedNamespace())) Found = true; R.resolveKind(); return Found; } static bool isNamespaceOrTranslationUnitScope(Scope *S) { if (DeclContext *Ctx = S->getEntity()) return Ctx->isFileContext(); return false; } // Find the next outer declaration context from this scope. This // routine actually returns the semantic outer context, which may // differ from the lexical context (encoded directly in the Scope // stack) when we are parsing a member of a class template. In this // case, the second element of the pair will be true, to indicate that // name lookup should continue searching in this semantic context when // it leaves the current template parameter scope. static std::pair findOuterContext(Scope *S) { DeclContext *DC = S->getEntity(); DeclContext *Lexical = nullptr; for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) { if (OuterS->getEntity()) { Lexical = OuterS->getEntity(); break; } } // C++ [temp.local]p8: // In the definition of a member of a class template that appears // outside of the namespace containing the class template // definition, the name of a template-parameter hides the name of // a member of this namespace. // // Example: // // namespace N { // class C { }; // // template class B { // void f(T); // }; // } // // template void N::B::f(C) { // C b; // C is the template parameter, not N::C // } // // In this example, the lexical context we return is the // TranslationUnit, while the semantic context is the namespace N. if (!Lexical || !DC || !S->getParent() || !S->getParent()->isTemplateParamScope()) return std::make_pair(Lexical, false); // Find the outermost template parameter scope. // For the example, this is the scope for the template parameters of // template. Scope *OutermostTemplateScope = S->getParent(); while (OutermostTemplateScope->getParent() && OutermostTemplateScope->getParent()->isTemplateParamScope()) OutermostTemplateScope = OutermostTemplateScope->getParent(); // Find the namespace context in which the original scope occurs. In // the example, this is namespace N. DeclContext *Semantic = DC; while (!Semantic->isFileContext()) Semantic = Semantic->getParent(); // Find the declaration context just outside of the template // parameter scope. This is the context in which the template is // being lexically declaration (a namespace context). In the // example, this is the global scope. if (Lexical->isFileContext() && !Lexical->Equals(Semantic) && Lexical->Encloses(Semantic)) return std::make_pair(Semantic, true); return std::make_pair(Lexical, false); } namespace { /// An RAII object to specify that we want to find block scope extern /// declarations. struct FindLocalExternScope { FindLocalExternScope(LookupResult &R) : R(R), OldFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_LocalExtern) { R.setFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_Ordinary); } void restore() { R.setFindLocalExtern(OldFindLocalExtern); } ~FindLocalExternScope() { restore(); } LookupResult &R; bool OldFindLocalExtern; }; } // end anonymous namespace bool Sema::CppLookupName(LookupResult &R, Scope *S) { assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup"); DeclarationName Name = R.getLookupName(); Sema::LookupNameKind NameKind = R.getLookupKind(); // If this is the name of an implicitly-declared special member function, // go through the scope stack to implicitly declare if (isImplicitlyDeclaredMemberFunctionName(Name)) { for (Scope *PreS = S; PreS; PreS = PreS->getParent()) if (DeclContext *DC = PreS->getEntity()) DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC); } // Implicitly declare member functions with the name we're looking for, if in // fact we are in a scope where it matters. Scope *Initial = S; IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); // First we lookup local scope. // We don't consider using-directives, as per 7.3.4.p1 [namespace.udir] // ...During unqualified name lookup (3.4.1), the names appear as if // they were declared in the nearest enclosing namespace which contains // both the using-directive and the nominated namespace. // [Note: in this context, "contains" means "contains directly or // indirectly". // // For example: // namespace A { int i; } // void foo() { // int i; // { // using namespace A; // ++i; // finds local 'i', A::i appears at global scope // } // } // UnqualUsingDirectiveSet UDirs; bool VisitedUsingDirectives = false; bool LeftStartingScope = false; DeclContext *OutsideOfTemplateParamDC = nullptr; // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { DeclContext *Ctx = S->getEntity(); bool SearchNamespaceScope = true; // Check whether the IdResolver has anything in this scope. for (; I != IEnd && S->isDeclScope(*I); ++I) { if (NamedDecl *ND = R.getAcceptableDecl(*I)) { if (NameKind == LookupRedeclarationWithLinkage && !(*I)->isTemplateParameter()) { // If it's a template parameter, we still find it, so we can diagnose // the invalid redeclaration. // Determine whether this (or a previous) declaration is // out-of-scope. if (!LeftStartingScope && !Initial->isDeclScope(*I)) LeftStartingScope = true; // If we found something outside of our starting scope that // does not have linkage, skip it. if (LeftStartingScope && !((*I)->hasLinkage())) { R.setShadowed(); continue; } } else { // We found something in this scope, we should not look at the // namespace scope SearchNamespaceScope = false; } R.addDecl(ND); } } if (!SearchNamespaceScope) { R.resolveKind(); if (S->isClassScope()) if (CXXRecordDecl *Record = dyn_cast_or_null(Ctx)) R.setNamingClass(Record); return true; } if (NameKind == LookupLocalFriendName && !S->isClassScope()) { // C++11 [class.friend]p11: // If a friend declaration appears in a local class and the name // specified is an unqualified name, a prior declaration is // looked up without considering scopes that are outside the // innermost enclosing non-class scope. return false; } if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && S->getParent() && !S->getParent()->isTemplateParamScope()) { // We've just searched the last template parameter scope and // found nothing, so look into the contexts between the // lexical and semantic declaration contexts returned by // findOuterContext(). This implements the name lookup behavior // of C++ [temp.local]p8. Ctx = OutsideOfTemplateParamDC; OutsideOfTemplateParamDC = nullptr; } if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); if (SearchAfterTemplateScope) OutsideOfTemplateParamDC = OuterCtx; for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing // non-transparent context. if (Ctx->isTransparentContext()) continue; // We do not look directly into function or method contexts, // since all of the local variables and parameters of the // function/method are present within the Scope. if (Ctx->isFunctionOrMethod()) { // If we have an Objective-C instance method, look for ivars // in the corresponding interface. if (ObjCMethodDecl *Method = dyn_cast(Ctx)) { if (Method->isInstanceMethod() && Name.getAsIdentifierInfo()) if (ObjCInterfaceDecl *Class = Method->getClassInterface()) { ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable( Name.getAsIdentifierInfo(), ClassDeclared)) { if (NamedDecl *ND = R.getAcceptableDecl(Ivar)) { R.addDecl(ND); R.resolveKind(); return true; } } } } continue; } // If this is a file context, we need to perform unqualified name // lookup considering using directives. if (Ctx->isFileContext()) { // If we haven't handled using directives yet, do so now. if (!VisitedUsingDirectives) { // Add using directives from this context up to the top level. for (DeclContext *UCtx = Ctx; UCtx; UCtx = UCtx->getParent()) { if (UCtx->isTransparentContext()) continue; UDirs.visit(UCtx, UCtx); } // Find the innermost file scope, so we can add using directives // from local scopes. Scope *InnermostFileScope = S; while (InnermostFileScope && !isNamespaceOrTranslationUnitScope(InnermostFileScope)) InnermostFileScope = InnermostFileScope->getParent(); UDirs.visitScopeChain(Initial, InnermostFileScope); UDirs.done(); VisitedUsingDirectives = true; } if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) { R.resolveKind(); return true; } continue; } // Perform qualified name lookup into this context. // FIXME: In some cases, we know that every name that could be found by // this qualified name lookup will also be on the identifier chain. For // example, inside a class without any base classes, we never need to // perform qualified lookup because all of the members are on top of the // identifier chain. if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true)) return true; } } } // Stop if we ran out of scopes. // FIXME: This really, really shouldn't be happening. if (!S) return false; // If we are looking for members, no need to look into global/namespace scope. if (NameKind == LookupMemberName) return false; // Collect UsingDirectiveDecls in all scopes, and recursively all // nominated namespaces by those using-directives. // // FIXME: Cache this sorted list in Scope structure, and DeclContext, so we // don't build it for each lookup! if (!VisitedUsingDirectives) { UDirs.visitScopeChain(Initial, S); UDirs.done(); } // If we're not performing redeclaration lookup, do not look for local // extern declarations outside of a function scope. if (!R.isForRedeclaration()) FindLocals.restore(); // Lookup namespace scope, and global scope. // Unqualified name lookup in C++ requires looking into scopes // that aren't strictly lexical, and therefore we walk through the // context as well as walking through the scopes. for (; S; S = S->getParent()) { // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(*I); ++I) { if (NamedDecl *ND = R.getAcceptableDecl(*I)) { // We found something. Look for anything else in our scope // with this same name and in an acceptable identifier // namespace, so that we can construct an overload set if we // need to. Found = true; R.addDecl(ND); } } if (Found && S->isTemplateParamScope()) { R.resolveKind(); return true; } DeclContext *Ctx = S->getEntity(); if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && S->getParent() && !S->getParent()->isTemplateParamScope()) { // We've just searched the last template parameter scope and // found nothing, so look into the contexts between the // lexical and semantic declaration contexts returned by // findOuterContext(). This implements the name lookup behavior // of C++ [temp.local]p8. Ctx = OutsideOfTemplateParamDC; OutsideOfTemplateParamDC = nullptr; } if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); if (SearchAfterTemplateScope) OutsideOfTemplateParamDC = OuterCtx; for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing // non-transparent context. if (Ctx->isTransparentContext()) continue; // If we have a context, and it's not a context stashed in the // template parameter scope for an out-of-line definition, also // look into that context. if (!(Found && S->isTemplateParamScope())) { assert(Ctx->isFileContext() && "We should have been looking only at file context here already."); // Look into context considering using-directives. if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) Found = true; } if (Found) { R.resolveKind(); return true; } if (R.isForRedeclaration() && !Ctx->isTransparentContext()) return false; } } if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext()) return false; } return !R.empty(); } -Module *Sema::getOwningModule(Decl *Entity) { - // If it's imported, grab its owning module. - Module *M = Entity->getImportedOwningModule(); - if (M || !isa(Entity) || !cast(Entity)->isHidden()) - return M; - assert(!Entity->isFromASTFile() && - "hidden entity from AST file has no owning module"); - - if (!getLangOpts().ModulesLocalVisibility) { - // If we're not tracking visibility locally, the only way a declaration - // can be hidden and local is if it's hidden because it's parent is (for - // instance, maybe this is a lazily-declared special member of an imported - // class). - auto *Parent = cast(Entity->getDeclContext()); - assert(Parent->isHidden() && "unexpectedly hidden decl"); - return getOwningModule(Parent); - } - - // It's local and hidden; grab or compute its owning module. - M = Entity->getLocalOwningModule(); - if (M) - return M; - - if (auto *Containing = - PP.getModuleContainingLocation(Entity->getLocation())) { - M = Containing; - } else if (Entity->isInvalidDecl() || Entity->getLocation().isInvalid()) { - // Don't bother tracking visibility for invalid declarations with broken - // locations. - cast(Entity)->setHidden(false); - } else { - // We need to assign a module to an entity that exists outside of any - // module, so that we can hide it from modules that we textually enter. - // Invent a fake module for all such entities. - if (!CachedFakeTopLevelModule) { - CachedFakeTopLevelModule = - PP.getHeaderSearchInfo().getModuleMap().findOrCreateModule( - "", nullptr, false, false).first; - - auto &SrcMgr = PP.getSourceManager(); - SourceLocation StartLoc = - SrcMgr.getLocForStartOfFile(SrcMgr.getMainFileID()); - auto &TopLevel = ModuleScopes.empty() - ? VisibleModules - : ModuleScopes[0].OuterVisibleModules; - TopLevel.setVisible(CachedFakeTopLevelModule, StartLoc); - } - - M = CachedFakeTopLevelModule; - } - - if (M) - Entity->setLocalOwningModule(M); - return M; -} - void Sema::makeMergedDefinitionVisible(NamedDecl *ND) { if (auto *M = getCurrentModule()) Context.mergeDefinitionIntoModule(ND, M); else // We're not building a module; just make the definition visible. ND->setHidden(false); // If ND is a template declaration, make the template parameters // visible too. They're not (necessarily) within a mergeable DeclContext. if (auto *TD = dyn_cast(ND)) for (auto *Param : *TD->getTemplateParameters()) makeMergedDefinitionVisible(Param); } /// \brief Find the module in which the given declaration was defined. static Module *getDefiningModule(Sema &S, Decl *Entity) { if (FunctionDecl *FD = dyn_cast(Entity)) { // If this function was instantiated from a template, the defining module is // the module containing the pattern. if (FunctionDecl *Pattern = FD->getTemplateInstantiationPattern()) Entity = Pattern; } else if (CXXRecordDecl *RD = dyn_cast(Entity)) { if (CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern()) Entity = Pattern; } else if (EnumDecl *ED = dyn_cast(Entity)) { if (auto *Pattern = ED->getTemplateInstantiationPattern()) Entity = Pattern; } else if (VarDecl *VD = dyn_cast(Entity)) { if (VarDecl *Pattern = VD->getTemplateInstantiationPattern()) Entity = Pattern; } // Walk up to the containing context. That might also have been instantiated // from a template. DeclContext *Context = Entity->getDeclContext(); if (Context->isFileContext()) return S.getOwningModule(Entity); return getDefiningModule(S, cast(Context)); } llvm::DenseSet &Sema::getLookupModules() { unsigned N = CodeSynthesisContexts.size(); for (unsigned I = CodeSynthesisContextLookupModules.size(); I != N; ++I) { Module *M = getDefiningModule(*this, CodeSynthesisContexts[I].Entity); if (M && !LookupModulesCache.insert(M).second) M = nullptr; CodeSynthesisContextLookupModules.push_back(M); } return LookupModulesCache; } bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) { for (Module *Merged : Context.getModulesWithMergedDefinition(Def)) if (isModuleVisible(Merged)) return true; return false; } template static bool hasVisibleDefaultArgument(Sema &S, const ParmDecl *D, llvm::SmallVectorImpl *Modules) { if (!D->hasDefaultArgument()) return false; while (D) { auto &DefaultArg = D->getDefaultArgStorage(); if (!DefaultArg.isInherited() && S.isVisible(D)) return true; if (!DefaultArg.isInherited() && Modules) { auto *NonConstD = const_cast(D); Modules->push_back(S.getOwningModule(NonConstD)); const auto &Merged = S.Context.getModulesWithMergedDefinition(NonConstD); Modules->insert(Modules->end(), Merged.begin(), Merged.end()); } // If there was a previous default argument, maybe its parameter is visible. D = DefaultArg.getInheritedFrom(); } return false; } bool Sema::hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl *Modules) { if (auto *P = dyn_cast(D)) return ::hasVisibleDefaultArgument(*this, P, Modules); if (auto *P = dyn_cast(D)) return ::hasVisibleDefaultArgument(*this, P, Modules); return ::hasVisibleDefaultArgument(*this, cast(D), Modules); } bool Sema::hasVisibleMemberSpecialization( const NamedDecl *D, llvm::SmallVectorImpl *Modules) { assert(isa(D->getDeclContext()) && "not a member specialization"); for (auto *Redecl : D->redecls()) { // If the specialization is declared at namespace scope, then it's a member // specialization declaration. If it's lexically inside the class // definition then it was instantiated. // // FIXME: This is a hack. There should be a better way to determine this. // FIXME: What about MS-style explicit specializations declared within a // class definition? if (Redecl->getLexicalDeclContext()->isFileContext()) { auto *NonConstR = const_cast(cast(Redecl)); if (isVisible(NonConstR)) return true; if (Modules) { Modules->push_back(getOwningModule(NonConstR)); const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR); Modules->insert(Modules->end(), Merged.begin(), Merged.end()); } } } return false; } /// \brief Determine whether a declaration is visible to name lookup. /// /// This routine determines whether the declaration D is visible in the current /// lookup context, taking into account the current template instantiation /// stack. During template instantiation, a declaration is visible if it is /// visible from a module containing any entity on the template instantiation /// path (by instantiating a template, you allow it to see the declarations that /// your module can see, including those later on in your module). bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { assert(D->isHidden() && "should not call this: not in slow case"); Module *DeclModule = nullptr; if (SemaRef.getLangOpts().ModulesLocalVisibility) { DeclModule = SemaRef.getOwningModule(D); if (!DeclModule) { - // getOwningModule() may have decided the declaration should not be hidden. assert(!D->isHidden() && "hidden decl not from a module"); return true; } // If the owning module is visible, and the decl is not module private, // then the decl is visible too. (Module private is ignored within the same // top-level module.) if ((!D->isFromASTFile() || !D->isModulePrivate()) && (SemaRef.isModuleVisible(DeclModule) || SemaRef.hasVisibleMergedDefinition(D))) return true; } // If this declaration is not at namespace scope nor module-private, // then it is visible if its lexical parent has a visible definition. DeclContext *DC = D->getLexicalDeclContext(); if (!D->isModulePrivate() && DC && !DC->isFileContext() && !isa(DC) && !isa(DC)) { // For a parameter, check whether our current template declaration's // lexical context is visible, not whether there's some other visible // definition of it, because parameters aren't "within" the definition. // // In C++ we need to check for a visible definition due to ODR merging, // and in C we must not because each declaration of a function gets its own // set of declarations for tags in prototype scope. if ((D->isTemplateParameter() || isa(D) || (isa(DC) && !SemaRef.getLangOpts().CPlusPlus)) ? isVisible(SemaRef, cast(DC)) : SemaRef.hasVisibleDefinition(cast(DC))) { if (SemaRef.CodeSynthesisContexts.empty() && // FIXME: Do something better in this case. !SemaRef.getLangOpts().ModulesLocalVisibility) { // Cache the fact that this declaration is implicitly visible because // its parent has a visible definition. D->setHidden(false); } return true; } return false; } // Find the extra places where we need to look. llvm::DenseSet &LookupModules = SemaRef.getLookupModules(); if (LookupModules.empty()) return false; if (!DeclModule) { DeclModule = SemaRef.getOwningModule(D); assert(DeclModule && "hidden decl not from a module"); } // If our lookup set contains the decl's module, it's visible. if (LookupModules.count(DeclModule)) return true; // If the declaration isn't exported, it's not visible in any other module. if (D->isModulePrivate()) return false; // Check whether DeclModule is transitively exported to an import of // the lookup set. return std::any_of(LookupModules.begin(), LookupModules.end(), [&](Module *M) { return M->isModuleVisible(DeclModule); }); } bool Sema::isVisibleSlow(const NamedDecl *D) { return LookupResult::isVisible(*this, const_cast(D)); } bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) { for (auto *D : R) { if (isVisible(D)) return true; } return New->isExternallyVisible(); } /// \brief Retrieve the visible declaration corresponding to D, if any. /// /// This routine determines whether the declaration D is visible in the current /// module, with the current imports. If not, it checks whether any /// redeclaration of D is visible, and if so, returns that declaration. /// /// \returns D, or a visible previous declaration of D, whichever is more recent /// and visible. If no declaration of D is visible, returns null. static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case"); for (auto RD : D->redecls()) { // Don't bother with extra checks if we already know this one isn't visible. if (RD == D) continue; auto ND = cast(RD); // FIXME: This is wrong in the case where the previous declaration is not // visible in the same scope as D. This needs to be done much more // carefully. if (LookupResult::isVisible(SemaRef, ND)) return ND; } return nullptr; } bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D, llvm::SmallVectorImpl *Modules) { assert(!isVisible(D) && "not in slow case"); for (auto *Redecl : D->redecls()) { auto *NonConstR = const_cast(cast(Redecl)); if (isVisible(NonConstR)) return true; if (Modules) { Modules->push_back(getOwningModule(NonConstR)); const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR); Modules->insert(Modules->end(), Merged.begin(), Merged.end()); } } return false; } NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { if (auto *ND = dyn_cast(D)) { // Namespaces are a bit of a special case: we expect there to be a lot of // redeclarations of some namespaces, all declarations of a namespace are // essentially interchangeable, all declarations are found by name lookup // if any is, and namespaces are never looked up during template // instantiation. So we benefit from caching the check in this case, and // it is correct to do so. auto *Key = ND->getCanonicalDecl(); if (auto *Acceptable = getSema().VisibleNamespaceCache.lookup(Key)) return Acceptable; auto *Acceptable = isVisible(getSema(), Key) ? Key : findAcceptableDecl(getSema(), Key); if (Acceptable) getSema().VisibleNamespaceCache.insert(std::make_pair(Key, Acceptable)); return Acceptable; } return findAcceptableDecl(getSema(), D); } /// @brief Perform unqualified name lookup starting from a given /// scope. /// /// Unqualified name lookup (C++ [basic.lookup.unqual], C99 6.2.1) is /// used to find names within the current scope. For example, 'x' in /// @code /// int x; /// int f() { /// return x; // unqualified name look finds 'x' in the global scope /// } /// @endcode /// /// Different lookup criteria can find different names. For example, a /// particular scope can have both a struct and a function of the same /// name, and each can be found by certain lookup criteria. For more /// information about lookup criteria, see the documentation for the /// class LookupCriteria. /// /// @param S The scope from which unqualified name lookup will /// begin. If the lookup criteria permits, name lookup may also search /// in the parent scopes. /// /// @param [in,out] R Specifies the lookup to perform (e.g., the name to /// look up and the lookup kind), and is updated with the results of lookup /// including zero or more declarations and possibly additional information /// used to diagnose ambiguities. /// /// @returns \c true if lookup succeeded and false otherwise. bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { DeclarationName Name = R.getLookupName(); if (!Name) return false; LookupNameKind NameKind = R.getLookupKind(); if (!getLangOpts().CPlusPlus) { // Unqualified name lookup in C/Objective-C is purely lexical, so // search in the declarations attached to the name. if (NameKind == Sema::LookupRedeclarationWithLinkage) { // Find the nearest non-transparent declaration scope. while (!(S->getFlags() & Scope::DeclScope) || (S->getEntity() && S->getEntity()->isTransparentContext())) S = S->getParent(); } // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); // Scan up the scope chain looking for a decl that matches this // identifier that is in the appropriate namespace. This search // should not take long, as shadowing of names is uncommon, and // deep shadowing is extremely uncommon. bool LeftStartingScope = false; for (IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); I != IEnd; ++I) if (NamedDecl *D = R.getAcceptableDecl(*I)) { if (NameKind == LookupRedeclarationWithLinkage) { // Determine whether this (or a previous) declaration is // out-of-scope. if (!LeftStartingScope && !S->isDeclScope(*I)) LeftStartingScope = true; // If we found something outside of our starting scope that // does not have linkage, skip it. if (LeftStartingScope && !((*I)->hasLinkage())) { R.setShadowed(); continue; } } else if (NameKind == LookupObjCImplicitSelfParam && !isa(*I)) continue; R.addDecl(D); // Check whether there are any other declarations with the same name // and in the same scope. if (I != IEnd) { // Find the scope in which this declaration was declared (if it // actually exists in a Scope). while (S && !S->isDeclScope(D)) S = S->getParent(); // If the scope containing the declaration is the translation unit, // then we'll need to perform our checks based on the matching // DeclContexts rather than matching scopes. if (S && isNamespaceOrTranslationUnitScope(S)) S = nullptr; // Compute the DeclContext, if we need it. DeclContext *DC = nullptr; if (!S) DC = (*I)->getDeclContext()->getRedeclContext(); IdentifierResolver::iterator LastI = I; for (++LastI; LastI != IEnd; ++LastI) { if (S) { // Match based on scope. if (!S->isDeclScope(*LastI)) break; } else { // Match based on DeclContext. DeclContext *LastDC = (*LastI)->getDeclContext()->getRedeclContext(); if (!LastDC->Equals(DC)) break; } // If the declaration is in the right namespace and visible, add it. if (NamedDecl *LastD = R.getAcceptableDecl(*LastI)) R.addDecl(LastD); } R.resolveKind(); } return true; } } else { // Perform C++ unqualified name lookup. if (CppLookupName(R, S)) return true; } // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. if (AllowBuiltinCreation && LookupBuiltin(*this, R)) return true; // If we didn't find a use of this identifier, the ExternalSource // may be able to handle the situation. // Note: some lookup failures are expected! // See e.g. R.isForRedeclaration(). return (ExternalSource && ExternalSource->LookupUnqualified(R, S)); } /// @brief Perform qualified name lookup in the namespaces nominated by /// using directives by the given context. /// /// C++98 [namespace.qual]p2: /// Given X::m (where X is a user-declared namespace), or given \::m /// (where X is the global namespace), let S be the set of all /// declarations of m in X and in the transitive closure of all /// namespaces nominated by using-directives in X and its used /// namespaces, except that using-directives are ignored in any /// namespace, including X, directly containing one or more /// declarations of m. No namespace is searched more than once in /// the lookup of a name. If S is the empty set, the program is /// ill-formed. Otherwise, if S has exactly one member, or if the /// context of the reference is a using-declaration /// (namespace.udecl), S is the required set of declarations of /// m. Otherwise if the use of m is not one that allows a unique /// declaration to be chosen from S, the program is ill-formed. /// /// C++98 [namespace.qual]p5: /// During the lookup of a qualified namespace member name, if the /// lookup finds more than one declaration of the member, and if one /// declaration introduces a class name or enumeration name and the /// other declarations either introduce the same object, the same /// enumerator or a set of functions, the non-type name hides the /// class or enumeration name if and only if the declarations are /// from the same namespace; otherwise (the declarations are from /// different namespaces), the program is ill-formed. static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, DeclContext *StartDC) { assert(StartDC->isFileContext() && "start context is not a file context"); DeclContext::udir_range UsingDirectives = StartDC->using_directives(); if (UsingDirectives.begin() == UsingDirectives.end()) return false; // We have at least added all these contexts to the queue. llvm::SmallPtrSet Visited; Visited.insert(StartDC); // We have not yet looked into these namespaces, much less added // their "using-children" to the queue. SmallVector Queue; // We have already looked into the initial namespace; seed the queue // with its using-children. for (auto *I : UsingDirectives) { NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace(); if (Visited.insert(ND).second) Queue.push_back(ND); } // The easiest way to implement the restriction in [namespace.qual]p5 // is to check whether any of the individual results found a tag // and, if so, to declare an ambiguity if the final result is not // a tag. bool FoundTag = false; bool FoundNonTag = false; LookupResult LocalR(LookupResult::Temporary, R); bool Found = false; while (!Queue.empty()) { NamespaceDecl *ND = Queue.pop_back_val(); // We go through some convolutions here to avoid copying results // between LookupResults. bool UseLocal = !R.empty(); LookupResult &DirectR = UseLocal ? LocalR : R; bool FoundDirect = LookupDirect(S, DirectR, ND); if (FoundDirect) { // First do any local hiding. DirectR.resolveKind(); // If the local result is a tag, remember that. if (DirectR.isSingleTagDecl()) FoundTag = true; else FoundNonTag = true; // Append the local results to the total results if necessary. if (UseLocal) { R.addAllDecls(LocalR); LocalR.clear(); } } // If we find names in this namespace, ignore its using directives. if (FoundDirect) { Found = true; continue; } for (auto I : ND->using_directives()) { NamespaceDecl *Nom = I->getNominatedNamespace(); if (Visited.insert(Nom).second) Queue.push_back(Nom); } } if (Found) { if (FoundTag && FoundNonTag) R.setAmbiguousQualifiedTagHiding(); else R.resolveKind(); } return Found; } /// \brief Callback that looks for any member of a class with the given name. static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); Path.Decls = BaseRecord->lookup(Name); return !Path.Decls.empty(); } /// \brief Determine whether the given set of member declarations contains only /// static members, nested types, and enumerators. template static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) { Decl *D = (*First)->getUnderlyingDecl(); if (isa(D) || isa(D) || isa(D)) return true; if (isa(D)) { // Determine whether all of the methods are static. bool AllMethodsAreStatic = true; for(; First != Last; ++First) { D = (*First)->getUnderlyingDecl(); if (!isa(D)) { assert(isa(D) && "Non-function must be a tag decl"); break; } if (!cast(D)->isStatic()) { AllMethodsAreStatic = false; break; } } if (AllMethodsAreStatic) return true; } return false; } /// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find /// names when the context of those names is explicit specified, e.g., /// "std::vector" or "x->member", or as part of unqualified name lookup. /// /// Different lookup criteria can find different names. For example, a /// particular scope can have both a struct and a function of the same /// name, and each can be found by certain lookup criteria. For more /// information about lookup criteria, see the documentation for the /// class LookupCriteria. /// /// \param R captures both the lookup criteria and any lookup results found. /// /// \param LookupCtx The context in which qualified name lookup will /// search. If the lookup criteria permits, name lookup may also search /// in the parent contexts or (for C++ classes) base classes. /// /// \param InUnqualifiedLookup true if this is qualified name lookup that /// occurs as part of unqualified name lookup. /// /// \returns true if lookup succeeded, false if it failed. bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup) { assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); if (!R.getLookupName()) return false; // Make sure that the declaration context is complete. assert((!isa(LookupCtx) || LookupCtx->isDependentContext() || cast(LookupCtx)->isCompleteDefinition() || cast(LookupCtx)->isBeingDefined()) && "Declaration context must already be complete!"); struct QualifiedLookupInScope { bool oldVal; DeclContext *Context; // Set flag in DeclContext informing debugger that we're looking for qualified name QualifiedLookupInScope(DeclContext *ctx) : Context(ctx) { oldVal = ctx->setUseQualifiedLookup(); } ~QualifiedLookupInScope() { Context->setUseQualifiedLookup(oldVal); } } QL(LookupCtx); if (LookupDirect(*this, R, LookupCtx)) { R.resolveKind(); if (isa(LookupCtx)) R.setNamingClass(cast(LookupCtx)); return true; } // Don't descend into implied contexts for redeclarations. // C++98 [namespace.qual]p6: // In a declaration for a namespace member in which the // declarator-id is a qualified-id, given that the qualified-id // for the namespace member has the form // nested-name-specifier unqualified-id // the unqualified-id shall name a member of the namespace // designated by the nested-name-specifier. // See also [class.mfct]p5 and [class.static.data]p2. if (R.isForRedeclaration()) return false; // If this is a namespace, look it up in the implied namespaces. if (LookupCtx->isFileContext()) return LookupQualifiedNameInUsingDirectives(*this, R, LookupCtx); // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. CXXRecordDecl *LookupRec = dyn_cast(LookupCtx); if (!LookupRec || !LookupRec->getDefinition()) return false; // If we're performing qualified name lookup into a dependent class, // then we are actually looking into a current instantiation. If we have any // dependent base classes, then we either have to delay lookup until // template instantiation time (at which point all bases will be available) // or we have to fail. if (!InUnqualifiedLookup && LookupRec->isDependentContext() && LookupRec->hasAnyDependentBases()) { R.setNotFoundInCurrentInstantiation(); return false; } // Perform lookup into our base classes. CXXBasePaths Paths; Paths.setOrigin(LookupRec); // Look for this member in our base classes bool (*BaseCallback)(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name) = nullptr; switch (R.getLookupKind()) { case LookupObjCImplicitSelfParam: case LookupOrdinaryName: case LookupMemberName: case LookupRedeclarationWithLinkage: case LookupLocalFriendName: BaseCallback = &CXXRecordDecl::FindOrdinaryMember; break; case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; case LookupAnyName: BaseCallback = &LookupAnyMember; break; case LookupOMPReductionName: BaseCallback = &CXXRecordDecl::FindOMPReductionMember; break; case LookupUsingDeclName: // This lookup is for redeclarations only. case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: case LookupLabel: // These lookups will never find a member in a C++ class (or base class). return false; case LookupNestedNameSpecifierName: BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember; break; } DeclarationName Name = R.getLookupName(); if (!LookupRec->lookupInBases( [=](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { return BaseCallback(Specifier, Path, Name); }, Paths)) return false; R.setNamingClass(LookupRec); // C++ [class.member.lookup]p2: // [...] If the resulting set of declarations are not all from // sub-objects of the same type, or the set has a nonstatic member // and includes members from distinct sub-objects, there is an // ambiguity and the program is ill-formed. Otherwise that set is // the result of the lookup. QualType SubobjectType; int SubobjectNumber = 0; AccessSpecifier SubobjectAccess = AS_none; for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); // Pick the best (i.e. most permissive i.e. numerically lowest) access // across all paths. SubobjectAccess = std::min(SubobjectAccess, Path->Access); // Determine whether we're looking at a distinct sub-object or not. if (SubobjectType.isNull()) { // This is the first subobject we've looked at. Record its type. SubobjectType = Context.getCanonicalType(PathElement.Base->getType()); SubobjectNumber = PathElement.SubobjectNumber; continue; } if (SubobjectType != Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of // different types. If the declaration sets aren't the same, this // lookup is ambiguous. if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) { CXXBasePaths::paths_iterator FirstPath = Paths.begin(); DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin(); DeclContext::lookup_iterator CurrentD = Path->Decls.begin(); while (FirstD != FirstPath->Decls.end() && CurrentD != Path->Decls.end()) { if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) break; ++FirstD; ++CurrentD; } if (FirstD == FirstPath->Decls.end() && CurrentD == Path->Decls.end()) continue; } R.setAmbiguousBaseSubobjectTypes(Paths); return true; } if (SubobjectNumber != PathElement.SubobjectNumber) { // We have a different subobject of the same type. // C++ [class.member.lookup]p5: // A static member, a nested type or an enumerator defined in // a base class T can unambiguously be found even if an object // has more than one base class subobject of type T. if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) continue; // We have found a nonstatic member name in multiple, distinct // subobjects. Name lookup is ambiguous. R.setAmbiguousBaseSubobjects(Paths); return true; } } // Lookup in a base class succeeded; return these results. for (auto *D : Paths.front().Decls) { AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, D->getAccess()); R.addDecl(D, AS); } R.resolveKind(); return true; } /// \brief Performs qualified name lookup or special type of lookup for /// "__super::" scope specifier. /// /// This routine is a convenience overload meant to be called from contexts /// that need to perform a qualified name lookup with an optional C++ scope /// specifier that might require special kind of lookup. /// /// \param R captures both the lookup criteria and any lookup results found. /// /// \param LookupCtx The context in which qualified name lookup will /// search. /// /// \param SS An optional C++ scope-specifier. /// /// \returns true if lookup succeeded, false if it failed. bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS) { auto *NNS = SS.getScopeRep(); if (NNS && NNS->getKind() == NestedNameSpecifier::Super) return LookupInSuper(R, NNS->getAsRecordDecl()); else return LookupQualifiedName(R, LookupCtx); } /// @brief Performs name lookup for a name that was parsed in the /// source code, and may contain a C++ scope specifier. /// /// This routine is a convenience routine meant to be called from /// contexts that receive a name and an optional C++ scope specifier /// (e.g., "N::M::x"). It will then perform either qualified or /// unqualified name lookup (with LookupQualifiedName or LookupName, /// respectively) on the given name and return those results. It will /// perform a special type of lookup for "__super::" scope specifier. /// /// @param S The scope from which unqualified name lookup will /// begin. /// /// @param SS An optional C++ scope-specifier, e.g., "::N::M". /// /// @param EnteringContext Indicates whether we are going to enter the /// context of the scope-specifier SS (if present). /// /// @returns True if any decls were found (but possibly ambiguous) bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation, bool EnteringContext) { if (SS && SS->isInvalid()) { // When the scope specifier is invalid, don't even look for // anything. return false; } if (SS && SS->isSet()) { NestedNameSpecifier *NNS = SS->getScopeRep(); if (NNS->getKind() == NestedNameSpecifier::Super) return LookupInSuper(R, NNS->getAsRecordDecl()); if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { // We have resolved the scope specifier to a particular declaration // contex, and will perform name lookup in that context. if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC)) return false; R.setContextRange(SS->getRange()); return LookupQualifiedName(R, DC); } // We could not resolve the scope specified to a specific declaration // context, which means that SS refers to an unknown specialization. // Name lookup can't find anything in this case. R.setNotFoundInCurrentInstantiation(); R.setContextRange(SS->getRange()); return false; } // Perform unqualified name lookup starting in the given scope. return LookupName(R, S, AllowBuiltinCreation); } /// \brief Perform qualified name lookup into all base classes of the given /// class. /// /// \param R captures both the lookup criteria and any lookup results found. /// /// \param Class The context in which qualified name lookup will /// search. Name lookup will search in all base classes merging the results. /// /// @returns True if any decls were found (but possibly ambiguous) bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) { // The access-control rules we use here are essentially the rules for // doing a lookup in Class that just magically skipped the direct // members of Class itself. That is, the naming class is Class, and the // access includes the access of the base. for (const auto &BaseSpec : Class->bases()) { CXXRecordDecl *RD = cast( BaseSpec.getType()->castAs()->getDecl()); LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind()); Result.setBaseObjectType(Context.getRecordType(Class)); LookupQualifiedName(Result, RD); // Copy the lookup results into the target, merging the base's access into // the path access. for (auto I = Result.begin(), E = Result.end(); I != E; ++I) { R.addDecl(I.getDecl(), CXXRecordDecl::MergeAccess(BaseSpec.getAccessSpecifier(), I.getAccess())); } Result.suppressDiagnostics(); } R.resolveKind(); R.setNamingClass(Class); return !R.empty(); } /// \brief Produce a diagnostic describing the ambiguity that resulted /// from name lookup. /// /// \param Result The result of the ambiguous lookup to be diagnosed. void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { assert(Result.isAmbiguous() && "Lookup result must be ambiguous"); DeclarationName Name = Result.getLookupName(); SourceLocation NameLoc = Result.getNameLoc(); SourceRange LookupRange = Result.getContextRange(); switch (Result.getAmbiguityKind()) { case LookupResult::AmbiguousBaseSubobjects: { CXXBasePaths *Paths = Result.getBasePaths(); QualType SubobjectType = Paths->front().back().Base->getType(); Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) << LookupRange; DeclContext::lookup_iterator Found = Paths->front().Decls.begin(); while (isa(*Found) && cast(*Found)->isStatic()) ++Found; Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); break; } case LookupResult::AmbiguousBaseSubobjectTypes: { Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types) << Name << LookupRange; CXXBasePaths *Paths = Result.getBasePaths(); std::set DeclsPrinted; for (CXXBasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end(); Path != PathEnd; ++Path) { Decl *D = Path->Decls.front(); if (DeclsPrinted.insert(D).second) Diag(D->getLocation(), diag::note_ambiguous_member_found); } break; } case LookupResult::AmbiguousTagHiding: { Diag(NameLoc, diag::err_ambiguous_tag_hiding) << Name << LookupRange; llvm::SmallPtrSet TagDecls; for (auto *D : Result) if (TagDecl *TD = dyn_cast(D)) { TagDecls.insert(TD); Diag(TD->getLocation(), diag::note_hidden_tag); } for (auto *D : Result) if (!isa(D)) Diag(D->getLocation(), diag::note_hiding_object); // For recovery purposes, go ahead and implement the hiding. LookupResult::Filter F = Result.makeFilter(); while (F.hasNext()) { if (TagDecls.count(F.next())) F.erase(); } F.done(); break; } case LookupResult::AmbiguousReference: { Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; for (auto *D : Result) Diag(D->getLocation(), diag::note_ambiguous_candidate) << D; break; } } } namespace { struct AssociatedLookup { AssociatedLookup(Sema &S, SourceLocation InstantiationLoc, Sema::AssociatedNamespaceSet &Namespaces, Sema::AssociatedClassSet &Classes) : S(S), Namespaces(Namespaces), Classes(Classes), InstantiationLoc(InstantiationLoc) { } Sema &S; Sema::AssociatedNamespaceSet &Namespaces; Sema::AssociatedClassSet &Classes; SourceLocation InstantiationLoc; }; } // end anonymous namespace static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType T); static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, DeclContext *Ctx) { // Add the associated namespace for this class. // We don't use DeclContext::getEnclosingNamespaceContext() as this may // be a locally scoped record. // We skip out of inline namespaces. The innermost non-inline namespace // contains all names of all its nested inline namespaces anyway, so we can // replace the entire inline namespace tree with its root. while (Ctx->isRecord() || Ctx->isTransparentContext() || Ctx->isInlineNamespace()) Ctx = Ctx->getParent(); if (Ctx->isFileContext()) Namespaces.insert(Ctx->getPrimaryContext()); } // \brief Add the associated classes and namespaces for argument-dependent // lookup that involves a template argument (C++ [basic.lookup.koenig]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, const TemplateArgument &Arg) { // C++ [basic.lookup.koenig]p2, last bullet: // -- [...] ; switch (Arg.getKind()) { case TemplateArgument::Null: break; case TemplateArgument::Type: // [...] the namespaces and classes associated with the types of the // template arguments provided for template type parameters (excluding // template template parameters) addAssociatedClassesAndNamespaces(Result, Arg.getAsType()); break; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { // [...] the namespaces in which any template template arguments are // defined; and the classes in which any member templates used as // template template arguments are defined. TemplateName Template = Arg.getAsTemplateOrTemplatePattern(); if (ClassTemplateDecl *ClassTemplate = dyn_cast(Template.getAsTemplateDecl())) { DeclContext *Ctx = ClassTemplate->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); } break; } case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Expression: case TemplateArgument::NullPtr: // [Note: non-type template arguments do not contribute to the set of // associated namespaces. ] break; case TemplateArgument::Pack: for (const auto &P : Arg.pack_elements()) addAssociatedClassesAndNamespaces(Result, P); break; } } // \brief Add the associated classes and namespaces for // argument-dependent lookup with an argument of class type // (C++ [basic.lookup.koenig]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, CXXRecordDecl *Class) { // Just silently ignore anything whose name is __va_list_tag. if (Class->getDeclName() == Result.S.VAListTagName) return; // C++ [basic.lookup.koenig]p2: // [...] // -- If T is a class type (including unions), its associated // classes are: the class itself; the class of which it is a // member, if any; and its direct and indirect base // classes. Its associated namespaces are the namespaces in // which its associated classes are defined. // Add the class of which it is a member, if any. DeclContext *Ctx = Class->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); // Add the class itself. If we've already seen this class, we don't // need to visit base classes. // // FIXME: That's not correct, we may have added this class only because it // was the enclosing class of another class, and in that case we won't have // added its base classes yet. if (!Result.Classes.insert(Class)) return; // -- If T is a template-id, its associated namespaces and classes are // the namespace in which the template is defined; for member // templates, the member template's class; the namespaces and classes // associated with the types of the template arguments provided for // template type parameters (excluding template template parameters); the // namespaces in which any template template arguments are defined; and // the classes in which any member templates used as template template // arguments are defined. [Note: non-type template arguments do not // contribute to the set of associated namespaces. ] if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Class)) { DeclContext *Ctx = Spec->getSpecializedTemplate()->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) addAssociatedClassesAndNamespaces(Result, TemplateArgs[I]); } // Only recurse into base classes for complete types. if (!Result.S.isCompleteType(Result.InstantiationLoc, Result.S.Context.getRecordType(Class))) return; // Add direct and indirect base classes along with their associated // namespaces. SmallVector Bases; Bases.push_back(Class); while (!Bases.empty()) { // Pop this class off the stack. Class = Bases.pop_back_val(); // Visit the base classes. for (const auto &Base : Class->bases()) { const RecordType *BaseType = Base.getType()->getAs(); // In dependent contexts, we do ADL twice, and the first time around, // the base type might be a dependent TemplateSpecializationType, or a // TemplateTypeParmType. If that happens, simply ignore it. // FIXME: If we want to support export, we probably need to add the // namespace of the template in a TemplateSpecializationType, or even // the classes and namespaces of known non-dependent arguments. if (!BaseType) continue; CXXRecordDecl *BaseDecl = cast(BaseType->getDecl()); if (Result.Classes.insert(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); CollectEnclosingNamespace(Result.Namespaces, BaseCtx); // Make sure we visit the bases of this base class. if (BaseDecl->bases_begin() != BaseDecl->bases_end()) Bases.push_back(BaseDecl); } } } } // \brief Add the associated classes and namespaces for // argument-dependent lookup with an argument of type T // (C++ [basic.lookup.koenig]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // C++ [basic.lookup.koenig]p2: // // For each argument type T in the function call, there is a set // of zero or more associated namespaces and a set of zero or more // associated classes to be considered. The sets of namespaces and // classes is determined entirely by the types of the function // arguments (and the namespace of any template template // argument). Typedef names and using-declarations used to specify // the types do not contribute to this set. The sets of namespaces // and classes are determined in the following way: SmallVector Queue; const Type *T = Ty->getCanonicalTypeInternal().getTypePtr(); while (true) { switch (T->getTypeClass()) { #define TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" // T is canonical. We can also ignore dependent types because // we don't need to do ADL at the definition point, but if we // wanted to implement template export (or if we find some other // use for associated classes and namespaces...) this would be // wrong. break; // -- If T is a pointer to U or an array of U, its associated // namespaces and classes are those associated with U. case Type::Pointer: T = cast(T)->getPointeeType().getTypePtr(); continue; case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: T = cast(T)->getElementType().getTypePtr(); continue; // -- If T is a fundamental type, its associated sets of // namespaces and classes are both empty. case Type::Builtin: break; // -- If T is a class type (including unions), its associated // classes are: the class itself; the class of which it is a // member, if any; and its direct and indirect base // classes. Its associated namespaces are the namespaces in // which its associated classes are defined. case Type::Record: { CXXRecordDecl *Class = cast(cast(T)->getDecl()); addAssociatedClassesAndNamespaces(Result, Class); break; } // -- If T is an enumeration type, its associated namespace is // the namespace in which it is defined. If it is class // member, its associated class is the member's class; else // it has no associated class. case Type::Enum: { EnumDecl *Enum = cast(T)->getDecl(); DeclContext *Ctx = Enum->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); break; } // -- If T is a function type, its associated namespaces and // classes are those associated with the function parameter // types and those associated with the return type. case Type::FunctionProto: { const FunctionProtoType *Proto = cast(T); for (const auto &Arg : Proto->param_types()) Queue.push_back(Arg.getTypePtr()); // fallthrough } case Type::FunctionNoProto: { const FunctionType *FnType = cast(T); T = FnType->getReturnType().getTypePtr(); continue; } // -- If T is a pointer to a member function of a class X, its // associated namespaces and classes are those associated // with the function parameter types and return type, // together with those associated with X. // // -- If T is a pointer to a data member of class X, its // associated namespaces and classes are those associated // with the member type together with those associated with // X. case Type::MemberPointer: { const MemberPointerType *MemberPtr = cast(T); // Queue up the class type into which this points. Queue.push_back(MemberPtr->getClass()); // And directly continue with the pointee type. T = MemberPtr->getPointeeType().getTypePtr(); continue; } // As an extension, treat this like a normal pointer. case Type::BlockPointer: T = cast(T)->getPointeeType().getTypePtr(); continue; // References aren't covered by the standard, but that's such an // obvious defect that we cover them anyway. case Type::LValueReference: case Type::RValueReference: T = cast(T)->getPointeeType().getTypePtr(); continue; // These are fundamental types. case Type::Vector: case Type::ExtVector: case Type::Complex: break; // Non-deduced auto types only get here for error cases. case Type::Auto: case Type::DeducedTemplateSpecialization: break; // If T is an Objective-C object or interface type, or a pointer to an // object or interface type, the associated namespace is the global // namespace. case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: Result.Namespaces.insert(Result.S.Context.getTranslationUnitDecl()); break; // Atomic types are just wrappers; use the associations of the // contained type. case Type::Atomic: T = cast(T)->getValueType().getTypePtr(); continue; case Type::Pipe: T = cast(T)->getElementType().getTypePtr(); continue; } if (Queue.empty()) break; T = Queue.pop_back_val(); } } /// \brief Find the associated classes and namespaces for /// argument-dependent lookup for a call with the given set of /// arguments. /// /// This routine computes the sets of associated classes and associated /// namespaces searched by argument-dependent lookup /// (C++ [basic.lookup.argdep]) for a given set of arguments. void Sema::FindAssociatedClassesAndNamespaces( SourceLocation InstantiationLoc, ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses) { AssociatedNamespaces.clear(); AssociatedClasses.clear(); AssociatedLookup Result(*this, InstantiationLoc, AssociatedNamespaces, AssociatedClasses); // C++ [basic.lookup.koenig]p2: // For each argument type T in the function call, there is a set // of zero or more associated namespaces and a set of zero or more // associated classes to be considered. The sets of namespaces and // classes is determined entirely by the types of the function // arguments (and the namespace of any template template // argument). for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) { Expr *Arg = Args[ArgIdx]; if (Arg->getType() != Context.OverloadTy) { addAssociatedClassesAndNamespaces(Result, Arg->getType()); continue; } // [...] In addition, if the argument is the name or address of a // set of overloaded functions and/or function templates, its // associated classes and namespaces are the union of those // associated with each of the members of the set: the namespace // in which the function or function template is defined and the // classes and namespaces associated with its (non-dependent) // parameter types and return type. Arg = Arg->IgnoreParens(); if (UnaryOperator *unaryOp = dyn_cast(Arg)) if (unaryOp->getOpcode() == UO_AddrOf) Arg = unaryOp->getSubExpr(); UnresolvedLookupExpr *ULE = dyn_cast(Arg); if (!ULE) continue; for (const auto *D : ULE->decls()) { // Look through any using declarations to find the underlying function. const FunctionDecl *FDecl = D->getUnderlyingDecl()->getAsFunction(); // Add the classes and namespaces associated with the parameter // types and return type of this function. addAssociatedClassesAndNamespaces(Result, FDecl->getType()); } } } NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl) { LookupResult R(*this, Name, Loc, NameKind, Redecl); LookupName(R, S); return R.getAsSingle(); } /// \brief Find the protocol with the given name, if any. ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl) { Decl *D = LookupSingleName(TUScope, II, IdLoc, LookupObjCProtocolName, Redecl); return cast_or_null(D); } void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions) { // C++ [over.match.oper]p3: // -- The set of non-member candidates is the result of the // unqualified lookup of operator@ in the context of the // expression according to the usual rules for name lookup in // unqualified function calls (3.4.2) except that all member // functions are ignored. DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName); LookupName(Operators, S); assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous"); Functions.append(Operators.begin(), Operators.end()); } Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis) { assert(CanDeclareSpecialMemberFunction(RD) && "doing special member lookup into record that isn't fully complete"); RD = RD->getDefinition(); if (RValueThis || ConstThis || VolatileThis) assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) && "constructors and destructors always have unqualified lvalue this"); if (ConstArg || VolatileArg) assert((SM != CXXDefaultConstructor && SM != CXXDestructor) && "parameter-less special members can't have qualified arguments"); // FIXME: Get the caller to pass in a location for the lookup. SourceLocation LookupLoc = RD->getLocation(); llvm::FoldingSetNodeID ID; ID.AddPointer(RD); ID.AddInteger(SM); ID.AddInteger(ConstArg); ID.AddInteger(VolatileArg); ID.AddInteger(RValueThis); ID.AddInteger(ConstThis); ID.AddInteger(VolatileThis); void *InsertPoint; SpecialMemberOverloadResultEntry *Result = SpecialMemberCache.FindNodeOrInsertPos(ID, InsertPoint); // This was already cached if (Result) return *Result; Result = BumpAlloc.Allocate(); Result = new (Result) SpecialMemberOverloadResultEntry(ID); SpecialMemberCache.InsertNode(Result, InsertPoint); if (SM == CXXDestructor) { if (RD->needsImplicitDestructor()) DeclareImplicitDestructor(RD); CXXDestructorDecl *DD = RD->getDestructor(); assert(DD && "record without a destructor"); Result->setMethod(DD); Result->setKind(DD->isDeleted() ? SpecialMemberOverloadResult::NoMemberOrDeleted : SpecialMemberOverloadResult::Success); return *Result; } // Prepare for overload resolution. Here we construct a synthetic argument // if necessary and make sure that implicit functions are declared. CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(RD)); DeclarationName Name; Expr *Arg = nullptr; unsigned NumArgs; QualType ArgType = CanTy; ExprValueKind VK = VK_LValue; if (SM == CXXDefaultConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); NumArgs = 0; if (RD->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(RD); } else { if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); if (RD->needsImplicitCopyConstructor()) DeclareImplicitCopyConstructor(RD); if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(RD); } else { Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); if (RD->needsImplicitCopyAssignment()) DeclareImplicitCopyAssignment(RD); if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) DeclareImplicitMoveAssignment(RD); } if (ConstArg) ArgType.addConst(); if (VolatileArg) ArgType.addVolatile(); // This isn't /really/ specified by the standard, but it's implied // we should be working from an RValue in the case of move to ensure // that we prefer to bind to rvalue references, and an LValue in the // case of copy to ensure we don't bind to rvalue references. // Possibly an XValue is actually correct in the case of move, but // there is no semantic difference for class types in this restricted // case. if (SM == CXXCopyConstructor || SM == CXXCopyAssignment) VK = VK_LValue; else VK = VK_RValue; } OpaqueValueExpr FakeArg(LookupLoc, ArgType, VK); if (SM != CXXDefaultConstructor) { NumArgs = 1; Arg = &FakeArg; } // Create the object argument QualType ThisTy = CanTy; if (ConstThis) ThisTy.addConst(); if (VolatileThis) ThisTy.addVolatile(); Expr::Classification Classification = OpaqueValueExpr(LookupLoc, ThisTy, RValueThis ? VK_RValue : VK_LValue).Classify(Context); // Now we perform lookup on the name we computed earlier and do overload // resolution. Lookup is only performed directly into the class since there // will always be a (possibly implicit) declaration to shadow any others. OverloadCandidateSet OCS(LookupLoc, OverloadCandidateSet::CSK_Normal); DeclContext::lookup_result R = RD->lookup(Name); if (R.empty()) { // We might have no default constructor because we have a lambda's closure // type, rather than because there's some other declared constructor. // Every class has a copy/move constructor, copy/move assignment, and // destructor. assert(SM == CXXDefaultConstructor && "lookup for a constructor or assignment operator was empty"); Result->setMethod(nullptr); Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); return *Result; } // Copy the candidates as our processing of them may load new declarations // from an external source and invalidate lookup_result. SmallVector Candidates(R.begin(), R.end()); for (NamedDecl *CandDecl : Candidates) { if (CandDecl->isInvalidDecl()) continue; DeclAccessPair Cand = DeclAccessPair::make(CandDecl, AS_public); auto CtorInfo = getConstructorInfo(Cand); if (CXXMethodDecl *M = dyn_cast(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodCandidate(M, Cand, RD, ThisTy, Classification, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else if (CtorInfo) AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); } else if (FunctionTemplateDecl *Tmpl = dyn_cast(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodTemplateCandidate( Tmpl, Cand, RD, nullptr, ThisTy, Classification, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else if (CtorInfo) AddTemplateOverloadCandidate( CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else AddTemplateOverloadCandidate( Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); } else { assert(isa(Cand.getDecl()) && "illegal Kind of operator = Decl"); } } OverloadCandidateSet::iterator Best; switch (OCS.BestViableFunction(*this, LookupLoc, Best)) { case OR_Success: Result->setMethod(cast(Best->Function)); Result->setKind(SpecialMemberOverloadResult::Success); break; case OR_Deleted: Result->setMethod(cast(Best->Function)); Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); break; case OR_Ambiguous: Result->setMethod(nullptr); Result->setKind(SpecialMemberOverloadResult::Ambiguous); break; case OR_No_Viable_Function: Result->setMethod(nullptr); Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); break; } return *Result; } /// \brief Look up the default constructor for the given class. CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { SpecialMemberOverloadResult Result = LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false, false, false); return cast_or_null(Result.getMethod()); } /// \brief Look up the copying constructor for the given class. CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, unsigned Quals) { assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy ctor arg"); SpecialMemberOverloadResult Result = LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const, Quals & Qualifiers::Volatile, false, false, false); return cast_or_null(Result.getMethod()); } /// \brief Look up the moving constructor for the given class. CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class, unsigned Quals) { SpecialMemberOverloadResult Result = LookupSpecialMember(Class, CXXMoveConstructor, Quals & Qualifiers::Const, Quals & Qualifiers::Volatile, false, false, false); return cast_or_null(Result.getMethod()); } /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { // If the implicit constructors have not yet been declared, do so now. if (CanDeclareSpecialMemberFunction(Class)) { if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); if (Class->needsImplicitCopyConstructor()) DeclareImplicitCopyConstructor(Class); if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(Class); } CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T); return Class->lookup(Name); } /// \brief Look up the copying assignment operator for the given class. CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals) { assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment arg"); assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment this"); SpecialMemberOverloadResult Result = LookupSpecialMember(Class, CXXCopyAssignment, Quals & Qualifiers::Const, Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const, ThisQuals & Qualifiers::Volatile); return Result.getMethod(); } /// \brief Look up the moving assignment operator for the given class. CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals) { assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment this"); SpecialMemberOverloadResult Result = LookupSpecialMember(Class, CXXMoveAssignment, Quals & Qualifiers::Const, Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const, ThisQuals & Qualifiers::Volatile); return Result.getMethod(); } /// \brief Look for the destructor of the given class. /// /// During semantic analysis, this routine should be used in lieu of /// CXXRecordDecl::getDestructor(). /// /// \returns The destructor for this class. CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) { return cast(LookupSpecialMember(Class, CXXDestructor, false, false, false, false, false).getMethod()); } /// LookupLiteralOperator - Determine which literal operator should be used for /// a user-defined literal, per C++11 [lex.ext]. /// /// Normal overload resolution is not used to select which literal operator to /// call for a user-defined literal. Look up the provided literal operator name, /// and filter the results to the appropriate set for the given argument types. Sema::LiteralOperatorLookupResult Sema::LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef ArgTys, bool AllowRaw, bool AllowTemplate, bool AllowStringTemplate) { LookupName(R, S); assert(R.getResultKind() != LookupResult::Ambiguous && "literal operator lookup can't be ambiguous"); // Filter the lookup results appropriately. LookupResult::Filter F = R.makeFilter(); bool FoundRaw = false; bool FoundTemplate = false; bool FoundStringTemplate = false; bool FoundExactMatch = false; while (F.hasNext()) { Decl *D = F.next(); if (UsingShadowDecl *USD = dyn_cast(D)) D = USD->getTargetDecl(); // If the declaration we found is invalid, skip it. if (D->isInvalidDecl()) { F.erase(); continue; } bool IsRaw = false; bool IsTemplate = false; bool IsStringTemplate = false; bool IsExactMatch = false; if (FunctionDecl *FD = dyn_cast(D)) { if (FD->getNumParams() == 1 && FD->getParamDecl(0)->getType()->getAs()) IsRaw = true; else if (FD->getNumParams() == ArgTys.size()) { IsExactMatch = true; for (unsigned ArgIdx = 0; ArgIdx != ArgTys.size(); ++ArgIdx) { QualType ParamTy = FD->getParamDecl(ArgIdx)->getType(); if (!Context.hasSameUnqualifiedType(ArgTys[ArgIdx], ParamTy)) { IsExactMatch = false; break; } } } } if (FunctionTemplateDecl *FD = dyn_cast(D)) { TemplateParameterList *Params = FD->getTemplateParameters(); if (Params->size() == 1) IsTemplate = true; else IsStringTemplate = true; } if (IsExactMatch) { FoundExactMatch = true; AllowRaw = false; AllowTemplate = false; AllowStringTemplate = false; if (FoundRaw || FoundTemplate || FoundStringTemplate) { // Go through again and remove the raw and template decls we've // already found. F.restart(); FoundRaw = FoundTemplate = FoundStringTemplate = false; } } else if (AllowRaw && IsRaw) { FoundRaw = true; } else if (AllowTemplate && IsTemplate) { FoundTemplate = true; } else if (AllowStringTemplate && IsStringTemplate) { FoundStringTemplate = true; } else { F.erase(); } } F.done(); // C++11 [lex.ext]p3, p4: If S contains a literal operator with a matching // parameter type, that is used in preference to a raw literal operator // or literal operator template. if (FoundExactMatch) return LOLR_Cooked; // C++11 [lex.ext]p3, p4: S shall contain a raw literal operator or a literal // operator template, but not both. if (FoundRaw && FoundTemplate) { Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName(); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) NoteOverloadCandidate(*I, (*I)->getUnderlyingDecl()->getAsFunction()); return LOLR_Error; } if (FoundRaw) return LOLR_Raw; if (FoundTemplate) return LOLR_Template; if (FoundStringTemplate) return LOLR_StringTemplate; // Didn't find anything we could use. Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator) << R.getLookupName() << (int)ArgTys.size() << ArgTys[0] << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw << (AllowTemplate || AllowStringTemplate); return LOLR_Error; } void ADLResult::insert(NamedDecl *New) { NamedDecl *&Old = Decls[cast(New->getCanonicalDecl())]; // If we haven't yet seen a decl for this key, or the last decl // was exactly this one, we're done. if (Old == nullptr || Old == New) { Old = New; return; } // Otherwise, decide which is a more recent redeclaration. FunctionDecl *OldFD = Old->getAsFunction(); FunctionDecl *NewFD = New->getAsFunction(); FunctionDecl *Cursor = NewFD; while (true) { Cursor = Cursor->getPreviousDecl(); // If we got to the end without finding OldFD, OldFD is the newer // declaration; leave things as they are. if (!Cursor) return; // If we do find OldFD, then NewFD is newer. if (Cursor == OldFD) break; // Otherwise, keep looking. } Old = New; } void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, ArrayRef Args, ADLResult &Result) { // Find all of the associated namespaces and classes based on the // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; AssociatedClassSet AssociatedClasses; FindAssociatedClassesAndNamespaces(Loc, Args, AssociatedNamespaces, AssociatedClasses); // C++ [basic.lookup.argdep]p3: // Let X be the lookup set produced by unqualified lookup (3.4.1) // and let Y be the lookup set produced by argument dependent // lookup (defined as follows). If X contains [...] then Y is // empty. Otherwise Y is the set of declarations found in the // namespaces associated with the argument types as described // below. The set of declarations found by the lookup of the name // is the union of X and Y. // // Here, we compute Y and add its members to the overloaded // candidate set. for (auto *NS : AssociatedNamespaces) { // When considering an associated namespace, the lookup is the // same as the lookup performed when the associated namespace is // used as a qualifier (3.4.3.2) except that: // // -- Any using-directives in the associated namespace are // ignored. // // -- Any namespace-scope friend functions declared in // associated classes are visible within their respective // namespaces even if they are not visible during an ordinary // lookup (11.4). DeclContext::lookup_result R = NS->lookup(Name); for (auto *D : R) { // If the only declaration here is an ordinary friend, consider // it only if it was declared in an associated classes. if ((D->getIdentifierNamespace() & Decl::IDNS_Ordinary) == 0) { // If it's neither ordinarily visible nor a friend, we can't find it. if ((D->getIdentifierNamespace() & Decl::IDNS_OrdinaryFriend) == 0) continue; bool DeclaredInAssociatedClass = false; for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) { DeclContext *LexDC = DI->getLexicalDeclContext(); if (isa(LexDC) && AssociatedClasses.count(cast(LexDC)) && isVisible(cast(DI))) { DeclaredInAssociatedClass = true; break; } } if (!DeclaredInAssociatedClass) continue; } if (isa(D)) D = cast(D)->getTargetDecl(); if (!isa(D) && !isa(D)) continue; if (!isVisible(D) && !(D = findAcceptableDecl(*this, D))) continue; Result.insert(D); } } } //---------------------------------------------------------------------------- // Search for all visible declarations. //---------------------------------------------------------------------------- VisibleDeclConsumer::~VisibleDeclConsumer() { } bool VisibleDeclConsumer::includeHiddenDecls() const { return false; } namespace { class ShadowContextRAII; class VisibleDeclsRecord { public: /// \brief An entry in the shadow map, which is optimized to store a /// single declaration (the common case) but can also store a list /// of declarations. typedef llvm::TinyPtrVector ShadowMapEntry; private: /// \brief A mapping from declaration names to the declarations that have /// this name within a particular scope. typedef llvm::DenseMap ShadowMap; /// \brief A list of shadow maps, which is used to model name hiding. std::list ShadowMaps; /// \brief The declaration contexts we have already visited. llvm::SmallPtrSet VisitedContexts; friend class ShadowContextRAII; public: /// \brief Determine whether we have already visited this context /// (and, if not, note that we are going to visit that context now). bool visitedContext(DeclContext *Ctx) { return !VisitedContexts.insert(Ctx).second; } bool alreadyVisitedContext(DeclContext *Ctx) { return VisitedContexts.count(Ctx); } /// \brief Determine whether the given declaration is hidden in the /// current scope. /// /// \returns the declaration that hides the given declaration, or /// NULL if no such declaration exists. NamedDecl *checkHidden(NamedDecl *ND); /// \brief Add a declaration to the current shadow map. void add(NamedDecl *ND) { ShadowMaps.back()[ND->getDeclName()].push_back(ND); } }; /// \brief RAII object that records when we've entered a shadow context. class ShadowContextRAII { VisibleDeclsRecord &Visible; typedef VisibleDeclsRecord::ShadowMap ShadowMap; public: ShadowContextRAII(VisibleDeclsRecord &Visible) : Visible(Visible) { Visible.ShadowMaps.emplace_back(); } ~ShadowContextRAII() { Visible.ShadowMaps.pop_back(); } }; } // end anonymous namespace NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { unsigned IDNS = ND->getIdentifierNamespace(); std::list::reverse_iterator SM = ShadowMaps.rbegin(); for (std::list::reverse_iterator SMEnd = ShadowMaps.rend(); SM != SMEnd; ++SM) { ShadowMap::iterator Pos = SM->find(ND->getDeclName()); if (Pos == SM->end()) continue; for (auto *D : Pos->second) { // A tag declaration does not hide a non-tag declaration. if (D->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; // Protocols are in distinct namespaces from everything else. if (((D->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) || (IDNS & Decl::IDNS_ObjCProtocol)) && D->getIdentifierNamespace() != IDNS) continue; // Functions and function templates in the same scope overload // rather than hide. FIXME: Look for hiding based on function // signatures! if (D->getUnderlyingDecl()->isFunctionOrFunctionTemplate() && ND->getUnderlyingDecl()->isFunctionOrFunctionTemplate() && SM == ShadowMaps.rbegin()) continue; // A shadow declaration that's created by a resolved using declaration // is not hidden by the same using declaration. if (isa(ND) && isa(D) && cast(ND)->getUsingDecl() == D) continue; // We've found a declaration that hides this one. return D; } } return nullptr; } static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool QualifiedNameLookup, bool InBaseClass, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited, bool IncludeDependentBases = false) { if (!Ctx) return; // Make sure we don't visit the same context twice. if (Visited.visitedContext(Ctx->getPrimaryContext())) return; // Outside C++, lookup results for the TU live on identifiers. if (isa(Ctx) && !Result.getSema().getLangOpts().CPlusPlus) { auto &S = Result.getSema(); auto &Idents = S.Context.Idents; // Ensure all external identifiers are in the identifier table. if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) { std::unique_ptr Iter(External->getIdentifiers()); for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next()) Idents.get(Name); } // Walk all lookup results in the TU for each identifier. for (const auto &Ident : Idents) { for (auto I = S.IdResolver.begin(Ident.getValue()), E = S.IdResolver.end(); I != E; ++I) { if (S.IdResolver.isDeclInScope(*I, Ctx)) { if (NamedDecl *ND = Result.getAcceptableDecl(*I)) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); Visited.add(ND); } } } } return; } if (CXXRecordDecl *Class = dyn_cast(Ctx)) Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. for (DeclContextLookupResult R : Ctx->lookups()) { for (auto *D : R) { if (auto *ND = Result.getAcceptableDecl(D)) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); Visited.add(ND); } } } // Traverse using directives for qualified name lookup. if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); for (auto I : Ctx->using_directives()) { LookupVisibleDecls(I->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited, IncludeDependentBases); } } // Traverse the contexts of inherited C++ classes. if (CXXRecordDecl *Record = dyn_cast(Ctx)) { if (!Record->hasDefinition()) return; for (const auto &B : Record->bases()) { QualType BaseType = B.getType(); RecordDecl *RD; if (BaseType->isDependentType()) { if (!IncludeDependentBases) { // Don't look into dependent bases, because name lookup can't look // there anyway. continue; } const auto *TST = BaseType->getAs(); if (!TST) continue; TemplateName TN = TST->getTemplateName(); const auto *TD = dyn_cast_or_null(TN.getAsTemplateDecl()); if (!TD) continue; RD = TD->getTemplatedDecl(); } else { const auto *Record = BaseType->getAs(); if (!Record) continue; RD = Record->getDecl(); } // FIXME: It would be nice to be able to determine whether referencing // a particular member would be ambiguous. For example, given // // struct A { int member; }; // struct B { int member; }; // struct C : A, B { }; // // void f(C *c) { c->### } // // accessing 'member' would result in an ambiguity. However, we // could be smart enough to qualify the member with the base // class, e.g., // // c->B::member // // or // // c->A::member // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(RD, Result, QualifiedNameLookup, true, Consumer, Visited, IncludeDependentBases); } } // Traverse the contexts of Objective-C classes. if (ObjCInterfaceDecl *IFace = dyn_cast(Ctx)) { // Traverse categories. for (auto *Cat : IFace->visible_categories()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer, Visited); } // Traverse protocols. for (auto *I : IFace->all_referenced_protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, Visited); } // Traverse the superclass. if (IFace->getSuperClass()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, true, Consumer, Visited); } // If there is an implementation, traverse it. We do this to find // synthesized ivars. if (IFace->getImplementation()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(IFace->getImplementation(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } else if (ObjCProtocolDecl *Protocol = dyn_cast(Ctx)) { for (auto *I : Protocol->protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, Visited); } } else if (ObjCCategoryDecl *Category = dyn_cast(Ctx)) { for (auto *I : Category->protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, Visited); } // If there is an implementation, traverse it. if (Category->getImplementation()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Category->getImplementation(), Result, QualifiedNameLookup, true, Consumer, Visited); } } } static void LookupVisibleDecls(Scope *S, LookupResult &Result, UnqualUsingDirectiveSet &UDirs, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited) { if (!S) return; if (!S->getEntity() || (!S->getParent() && !Visited.alreadyVisitedContext(S->getEntity())) || (S->getEntity())->isFunctionOrMethod()) { FindLocalExternScope FindLocals(Result); // Walk through the declarations in this Scope. for (auto *D : S->decls()) { if (NamedDecl *ND = dyn_cast(D)) if ((ND = Result.getAcceptableDecl(ND))) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false); Visited.add(ND); } } } // FIXME: C++ [temp.local]p8 DeclContext *Entity = nullptr; if (S->getEntity()) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. Entity = S->getEntity(); DeclContext *OuterCtx = findOuterContext(S).first; // FIXME for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { if (ObjCMethodDecl *Method = dyn_cast(Ctx)) { if (Method->isInstanceMethod()) { // For instance methods, look for ivars in the method's interface. LookupResult IvarResult(Result.getSema(), Result.getLookupName(), Result.getNameLoc(), Sema::LookupMemberName); if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } } // We've already performed all of the name lookup that we need // to for Objective-C methods; the next context will be the // outer scope. break; } if (Ctx->isFunctionOrMethod()) continue; LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } } else if (!S->getParent()) { // Look into the translation unit scope. We walk through the translation // unit's declaration context, because the Scope itself won't have all of // the declarations if we loaded a precompiled header. // FIXME: We would like the translation unit's Scope object to point to the // translation unit, so we don't need this special "if" branch. However, // doing so would force the normal C++ name-lookup code to look into the // translation unit decl when the IdentifierInfo chains would suffice. // Once we fix that problem (which is part of a more general "don't look // in DeclContexts unless we have to" optimization), we can eliminate this. Entity = Result.getSema().Context.getTranslationUnitDecl(); LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } if (Entity) { // Lookup visible declarations in any namespaces found by using // directives. for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity)) LookupVisibleDecls(const_cast(UUE.getNominatedNamespace()), Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } // Lookup names in the parent scope. ShadowContextRAII Shadow(Visited); LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited); } void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope) { // Determine the set of using directives available during // unqualified name lookup. Scope *Initial = S; UnqualUsingDirectiveSet UDirs; if (getLangOpts().CPlusPlus) { // Find the first namespace or translation-unit scope. while (S && !isNamespaceOrTranslationUnitScope(S)) S = S->getParent(); UDirs.visitScopeChain(Initial, S); } UDirs.done(); // Look for visible declarations. LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); Result.setAllowHidden(Consumer.includeHiddenDecls()); VisibleDeclsRecord Visited; if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited); } void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope, bool IncludeDependentBases) { LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); Result.setAllowHidden(Consumer.includeHiddenDecls()); VisibleDeclsRecord Visited; if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited, IncludeDependentBases); } /// LookupOrCreateLabel - Do a name lookup of a label with the specified name. /// If GnuLabelLoc is a valid source location, then this is a definition /// of an __label__ label name, otherwise it is a normal label definition /// or use. LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, SourceLocation GnuLabelLoc) { // Do a lookup to see if we have a label with this name already. NamedDecl *Res = nullptr; if (GnuLabelLoc.isValid()) { // Local label definitions always shadow existing labels. Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc); Scope *S = CurScope; PushOnScopeChains(Res, S, true); return cast(Res); } // Not a GNU local label. Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration); // If we found a label, check to see if it is in the same context as us. // When in a Block, we don't want to reuse a label in an enclosing function. if (Res && Res->getDeclContext() != CurContext) Res = nullptr; if (!Res) { // If not forward referenced or defined already, create the backing decl. Res = LabelDecl::Create(Context, CurContext, Loc, II); Scope *S = CurScope->getFnParent(); assert(S && "Not in a function?"); PushOnScopeChains(Res, S, true); } return cast(Res); } //===----------------------------------------------------------------------===// // Typo correction //===----------------------------------------------------------------------===// static bool isCandidateViable(CorrectionCandidateCallback &CCC, TypoCorrection &Candidate) { Candidate.setCallbackDistance(CCC.RankCandidate(Candidate)); return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance; } static void LookupPotentialTypoResult(Sema &SemaRef, LookupResult &Res, IdentifierInfo *Name, Scope *S, CXXScopeSpec *SS, DeclContext *MemberContext, bool EnteringContext, bool isObjCIvarLookup, bool FindHidden); /// \brief Check whether the declarations found for a typo correction are /// visible, and if none of them are, convert the correction to an 'import /// a module' correction. static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) { if (TC.begin() == TC.end()) return; TypoCorrection::decl_iterator DI = TC.begin(), DE = TC.end(); for (/**/; DI != DE; ++DI) if (!LookupResult::isVisible(SemaRef, *DI)) break; // Nothing to do if all decls are visible. if (DI == DE) return; llvm::SmallVector NewDecls(TC.begin(), DI); bool AnyVisibleDecls = !NewDecls.empty(); for (/**/; DI != DE; ++DI) { NamedDecl *VisibleDecl = *DI; if (!LookupResult::isVisible(SemaRef, *DI)) VisibleDecl = findAcceptableDecl(SemaRef, *DI); if (VisibleDecl) { if (!AnyVisibleDecls) { // Found a visible decl, discard all hidden ones. AnyVisibleDecls = true; NewDecls.clear(); } NewDecls.push_back(VisibleDecl); } else if (!AnyVisibleDecls && !(*DI)->isModulePrivate()) NewDecls.push_back(*DI); } if (NewDecls.empty()) TC = TypoCorrection(); else { TC.setCorrectionDecls(NewDecls); TC.setRequiresImport(!AnyVisibleDecls); } } // Fill the supplied vector with the IdentifierInfo pointers for each piece of // the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::", // fill the vector with the IdentifierInfo pointers for "foo" and "bar"). static void getNestedNameSpecifierIdentifiers( NestedNameSpecifier *NNS, SmallVectorImpl &Identifiers) { if (NestedNameSpecifier *Prefix = NNS->getPrefix()) getNestedNameSpecifierIdentifiers(Prefix, Identifiers); else Identifiers.clear(); const IdentifierInfo *II = nullptr; switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: II = NNS->getAsIdentifier(); break; case NestedNameSpecifier::Namespace: if (NNS->getAsNamespace()->isAnonymousNamespace()) return; II = NNS->getAsNamespace()->getIdentifier(); break; case NestedNameSpecifier::NamespaceAlias: II = NNS->getAsNamespaceAlias()->getIdentifier(); break; case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier(); break; case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: return; } if (II) Identifiers.push_back(II); } void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; // Only consider entities with identifiers for names, ignoring // special names (constructors, overloaded operators, selectors, // etc.). IdentifierInfo *Name = ND->getIdentifier(); if (!Name) return; // Only consider visible declarations and declarations from modules with // names that exactly match. if (!LookupResult::isVisible(SemaRef, ND) && Name != Typo && !findAcceptableDecl(SemaRef, ND)) return; FoundName(Name->getName()); } void TypoCorrectionConsumer::FoundName(StringRef Name) { // Compute the edit distance between the typo and the name of this // entity, and add the identifier to the list of results. addName(Name, nullptr); } void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) { // Compute the edit distance between the typo and this keyword, // and add the keyword to the list of results. addName(Keyword, nullptr, nullptr, true); } void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, NestedNameSpecifier *NNS, bool isKeyword) { // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. StringRef TypoStr = Typo->getName(); unsigned MinED = abs((int)Name.size() - (int)TypoStr.size()); if (MinED && TypoStr.size() / MinED < 3) return; // Compute an upper bound on the allowable edit distance, so that the // edit-distance algorithm can short-circuit. unsigned UpperBound = (TypoStr.size() + 2) / 3 + 1; unsigned ED = TypoStr.edit_distance(Name, true, UpperBound); if (ED >= UpperBound) return; TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, ED); if (isKeyword) TC.makeKeyword(); TC.setCorrectionRange(nullptr, Result.getLookupNameInfo()); addCorrection(TC); } static const unsigned MaxTypoDistanceResultSets = 5; void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { StringRef TypoStr = Typo->getName(); StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); // For very short typos, ignore potential corrections that have a different // base identifier from the typo or which have a normalized edit distance // longer than the typo itself. if (TypoStr.size() < 3 && (Name != TypoStr || Correction.getEditDistance(true) > TypoStr.size())) return; // If the correction is resolved but is not viable, ignore it. if (Correction.isResolved()) { checkCorrectionVisibility(SemaRef, Correction); if (!Correction || !isCandidateViable(*CorrectionValidator, Correction)) return; } TypoResultList &CList = CorrectionResults[Correction.getEditDistance(false)][Name]; if (!CList.empty() && !CList.back().isResolved()) CList.pop_back(); if (NamedDecl *NewND = Correction.getCorrectionDecl()) { std::string CorrectionStr = Correction.getAsString(SemaRef.getLangOpts()); for (TypoResultList::iterator RI = CList.begin(), RIEnd = CList.end(); RI != RIEnd; ++RI) { // If the Correction refers to a decl already in the result list, // replace the existing result if the string representation of Correction // comes before the current result alphabetically, then stop as there is // nothing more to be done to add Correction to the candidate set. if (RI->getCorrectionDecl() == NewND) { if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts())) *RI = Correction; return; } } } if (CList.empty() || Correction.isResolved()) CList.push_back(Correction); while (CorrectionResults.size() > MaxTypoDistanceResultSets) CorrectionResults.erase(std::prev(CorrectionResults.end())); } void TypoCorrectionConsumer::addNamespaces( const llvm::MapVector &KnownNamespaces) { SearchNamespaces = true; for (auto KNPair : KnownNamespaces) Namespaces.addNameSpecifier(KNPair.first); bool SSIsTemplate = false; if (NestedNameSpecifier *NNS = (SS && SS->isValid()) ? SS->getScopeRep() : nullptr) { if (const Type *T = NNS->getAsType()) SSIsTemplate = T->getTypeClass() == Type::TemplateSpecialization; } // Do not transform this into an iterator-based loop. The loop body can // trigger the creation of further types (through lazy deserialization) and // invalide iterators into this list. auto &Types = SemaRef.getASTContext().getTypes(); for (unsigned I = 0; I != Types.size(); ++I) { const auto *TI = Types[I]; if (CXXRecordDecl *CD = TI->getAsCXXRecordDecl()) { CD = CD->getCanonicalDecl(); if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() && !CD->isUnion() && CD->getIdentifier() && (SSIsTemplate || !isa(CD)) && (CD->isBeingDefined() || CD->isCompleteDefinition())) Namespaces.addNameSpecifier(CD); } } } const TypoCorrection &TypoCorrectionConsumer::getNextCorrection() { if (++CurrentTCIndex < ValidatedCorrections.size()) return ValidatedCorrections[CurrentTCIndex]; CurrentTCIndex = ValidatedCorrections.size(); while (!CorrectionResults.empty()) { auto DI = CorrectionResults.begin(); if (DI->second.empty()) { CorrectionResults.erase(DI); continue; } auto RI = DI->second.begin(); if (RI->second.empty()) { DI->second.erase(RI); performQualifiedLookups(); continue; } TypoCorrection TC = RI->second.pop_back_val(); if (TC.isResolved() || TC.requiresImport() || resolveCorrection(TC)) { ValidatedCorrections.push_back(TC); return ValidatedCorrections[CurrentTCIndex]; } } return ValidatedCorrections[0]; // The empty correction. } bool TypoCorrectionConsumer::resolveCorrection(TypoCorrection &Candidate) { IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo(); DeclContext *TempMemberContext = MemberContext; CXXScopeSpec *TempSS = SS.get(); retry_lookup: LookupPotentialTypoResult(SemaRef, Result, Name, S, TempSS, TempMemberContext, EnteringContext, CorrectionValidator->IsObjCIvarLookup, Name == Typo && !Candidate.WillReplaceSpecifier()); switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::FoundUnresolvedValue: if (TempSS) { // Immediately retry the lookup without the given CXXScopeSpec TempSS = nullptr; Candidate.WillReplaceSpecifier(true); goto retry_lookup; } if (TempMemberContext) { if (SS && !TempSS) TempSS = SS.get(); TempMemberContext = nullptr; goto retry_lookup; } if (SearchNamespaces) QualifiedResults.push_back(Candidate); break; case LookupResult::Ambiguous: // We don't deal with ambiguities. break; case LookupResult::Found: case LookupResult::FoundOverloaded: // Store all of the Decls for overloaded symbols for (auto *TRD : Result) Candidate.addCorrectionDecl(TRD); checkCorrectionVisibility(SemaRef, Candidate); if (!isCandidateViable(*CorrectionValidator, Candidate)) { if (SearchNamespaces) QualifiedResults.push_back(Candidate); break; } Candidate.setCorrectionRange(SS.get(), Result.getLookupNameInfo()); return true; } return false; } void TypoCorrectionConsumer::performQualifiedLookups() { unsigned TypoLen = Typo->getName().size(); for (const TypoCorrection &QR : QualifiedResults) { for (const auto &NSI : Namespaces) { DeclContext *Ctx = NSI.DeclCtx; const Type *NSType = NSI.NameSpecifier->getAsType(); // If the current NestedNameSpecifier refers to a class and the // current correction candidate is the name of that class, then skip // it as it is unlikely a qualified version of the class' constructor // is an appropriate correction. if (CXXRecordDecl *NSDecl = NSType ? NSType->getAsCXXRecordDecl() : nullptr) { if (NSDecl->getIdentifier() == QR.getCorrectionAsIdentifierInfo()) continue; } TypoCorrection TC(QR); TC.ClearCorrectionDecls(); TC.setCorrectionSpecifier(NSI.NameSpecifier); TC.setQualifierDistance(NSI.EditDistance); TC.setCallbackDistance(0); // Reset the callback distance // If the current correction candidate and namespace combination are // too far away from the original typo based on the normalized edit // distance, then skip performing a qualified name lookup. unsigned TmpED = TC.getEditDistance(true); if (QR.getCorrectionAsIdentifierInfo() != Typo && TmpED && TypoLen / TmpED < 3) continue; Result.clear(); Result.setLookupName(QR.getCorrectionAsIdentifierInfo()); if (!SemaRef.LookupQualifiedName(Result, Ctx)) continue; // Any corrections added below will be validated in subsequent // iterations of the main while() loop over the Consumer's contents. switch (Result.getResultKind()) { case LookupResult::Found: case LookupResult::FoundOverloaded: { if (SS && SS->isValid()) { std::string NewQualified = TC.getAsString(SemaRef.getLangOpts()); std::string OldQualified; llvm::raw_string_ostream OldOStream(OldQualified); SS->getScopeRep()->print(OldOStream, SemaRef.getPrintingPolicy()); OldOStream << Typo->getName(); // If correction candidate would be an identical written qualified // identifer, then the existing CXXScopeSpec probably included a // typedef that didn't get accounted for properly. if (OldOStream.str() == NewQualified) break; } for (LookupResult::iterator TRD = Result.begin(), TRDEnd = Result.end(); TRD != TRDEnd; ++TRD) { if (SemaRef.CheckMemberAccess(TC.getCorrectionRange().getBegin(), NSType ? NSType->getAsCXXRecordDecl() : nullptr, TRD.getPair()) == Sema::AR_accessible) TC.addCorrectionDecl(*TRD); } if (TC.isResolved()) { TC.setCorrectionRange(SS.get(), Result.getLookupNameInfo()); addCorrection(TC); } break; } case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: case LookupResult::FoundUnresolvedValue: break; } } } QualifiedResults.clear(); } TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet( ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec) : Context(Context), CurContextChain(buildContextChain(CurContext)) { if (NestedNameSpecifier *NNS = CurScopeSpec ? CurScopeSpec->getScopeRep() : nullptr) { llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier); NNS->print(SpecifierOStream, Context.getPrintingPolicy()); getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers); } // Build the list of identifiers that would be used for an absolute // (from the global context) NestedNameSpecifier referring to the current // context. for (DeclContext *C : llvm::reverse(CurContextChain)) { if (auto *ND = dyn_cast_or_null(C)) CurContextIdentifiers.push_back(ND->getIdentifier()); } // Add the global context as a NestedNameSpecifier SpecifierInfo SI = {cast(Context.getTranslationUnitDecl()), NestedNameSpecifier::GlobalSpecifier(Context), 1}; DistanceMap[1].push_back(SI); } auto TypoCorrectionConsumer::NamespaceSpecifierSet::buildContextChain( DeclContext *Start) -> DeclContextList { assert(Start && "Building a context chain from a null context"); DeclContextList Chain; for (DeclContext *DC = Start->getPrimaryContext(); DC != nullptr; DC = DC->getLookupParent()) { NamespaceDecl *ND = dyn_cast_or_null(DC); if (!DC->isInlineNamespace() && !DC->isTransparentContext() && !(ND && ND->isAnonymousNamespace())) Chain.push_back(DC->getPrimaryContext()); } return Chain; } unsigned TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier( DeclContextList &DeclChain, NestedNameSpecifier *&NNS) { unsigned NumSpecifiers = 0; for (DeclContext *C : llvm::reverse(DeclChain)) { if (auto *ND = dyn_cast_or_null(C)) { NNS = NestedNameSpecifier::Create(Context, NNS, ND); ++NumSpecifiers; } else if (auto *RD = dyn_cast_or_null(C)) { NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(), RD->getTypeForDecl()); ++NumSpecifiers; } } return NumSpecifiers; } void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( DeclContext *Ctx) { NestedNameSpecifier *NNS = nullptr; unsigned NumSpecifiers = 0; DeclContextList NamespaceDeclChain(buildContextChain(Ctx)); DeclContextList FullNamespaceDeclChain(NamespaceDeclChain); // Eliminate common elements from the two DeclContext chains. for (DeclContext *C : llvm::reverse(CurContextChain)) { if (NamespaceDeclChain.empty() || NamespaceDeclChain.back() != C) break; NamespaceDeclChain.pop_back(); } // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain NumSpecifiers = buildNestedNameSpecifier(NamespaceDeclChain, NNS); // Add an explicit leading '::' specifier if needed. if (NamespaceDeclChain.empty()) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = buildNestedNameSpecifier(FullNamespaceDeclChain, NNS); } else if (NamedDecl *ND = dyn_cast_or_null(NamespaceDeclChain.back())) { IdentifierInfo *Name = ND->getIdentifier(); bool SameNameSpecifier = false; if (std::find(CurNameSpecifierIdentifiers.begin(), CurNameSpecifierIdentifiers.end(), Name) != CurNameSpecifierIdentifiers.end()) { std::string NewNameSpecifier; llvm::raw_string_ostream SpecifierOStream(NewNameSpecifier); SmallVector NewNameSpecifierIdentifiers; getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); NNS->print(SpecifierOStream, Context.getPrintingPolicy()); SpecifierOStream.flush(); SameNameSpecifier = NewNameSpecifier == CurNameSpecifier; } if (SameNameSpecifier || std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(), Name) != CurContextIdentifiers.end()) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = buildNestedNameSpecifier(FullNamespaceDeclChain, NNS); } } // If the built NestedNameSpecifier would be replacing an existing // NestedNameSpecifier, use the number of component identifiers that // would need to be changed as the edit distance instead of the number // of components in the built NestedNameSpecifier. if (NNS && !CurNameSpecifierIdentifiers.empty()) { SmallVector NewNameSpecifierIdentifiers; getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); NumSpecifiers = llvm::ComputeEditDistance( llvm::makeArrayRef(CurNameSpecifierIdentifiers), llvm::makeArrayRef(NewNameSpecifierIdentifiers)); } SpecifierInfo SI = {Ctx, NNS, NumSpecifiers}; DistanceMap[NumSpecifiers].push_back(SI); } /// \brief Perform name lookup for a possible result for typo correction. static void LookupPotentialTypoResult(Sema &SemaRef, LookupResult &Res, IdentifierInfo *Name, Scope *S, CXXScopeSpec *SS, DeclContext *MemberContext, bool EnteringContext, bool isObjCIvarLookup, bool FindHidden) { Res.suppressDiagnostics(); Res.clear(); Res.setLookupName(Name); Res.setAllowHidden(FindHidden); if (MemberContext) { if (ObjCInterfaceDecl *Class = dyn_cast(MemberContext)) { if (isObjCIvarLookup) { if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(Name)) { Res.addDecl(Ivar); Res.resolveKind(); return; } } if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration( Name, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { Res.addDecl(Prop); Res.resolveKind(); return; } } SemaRef.LookupQualifiedName(Res, MemberContext); return; } SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, EnteringContext); // Fake ivar lookup; this should really be part of // LookupParsedName. if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) { if (Method->isInstanceMethod() && Method->getClassInterface() && (Res.empty() || (Res.isSingleResult() && Res.getFoundDecl()->isDefinedOutsideFunctionOrMethod()))) { if (ObjCIvarDecl *IV = Method->getClassInterface()->lookupInstanceVariable(Name)) { Res.addDecl(IV); Res.resolveKind(); } } } } /// \brief Add keywords to the consumer as possible typo corrections. static void AddKeywordsToConsumer(Sema &SemaRef, TypoCorrectionConsumer &Consumer, Scope *S, CorrectionCandidateCallback &CCC, bool AfterNestedNameSpecifier) { if (AfterNestedNameSpecifier) { // For 'X::', we know exactly which keywords can appear next. Consumer.addKeywordResult("template"); if (CCC.WantExpressionKeywords) Consumer.addKeywordResult("operator"); return; } if (CCC.WantObjCSuper) Consumer.addKeywordResult("super"); if (CCC.WantTypeSpecifiers) { // Add type-specifier keywords to the set of results. static const char *const CTypeSpecs[] = { "char", "const", "double", "enum", "float", "int", "long", "short", "signed", "struct", "union", "unsigned", "void", "volatile", "_Complex", "_Imaginary", // storage-specifiers as well "extern", "inline", "static", "typedef" }; const unsigned NumCTypeSpecs = llvm::array_lengthof(CTypeSpecs); for (unsigned I = 0; I != NumCTypeSpecs; ++I) Consumer.addKeywordResult(CTypeSpecs[I]); if (SemaRef.getLangOpts().C99) Consumer.addKeywordResult("restrict"); if (SemaRef.getLangOpts().Bool || SemaRef.getLangOpts().CPlusPlus) Consumer.addKeywordResult("bool"); else if (SemaRef.getLangOpts().C99) Consumer.addKeywordResult("_Bool"); if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("class"); Consumer.addKeywordResult("typename"); Consumer.addKeywordResult("wchar_t"); if (SemaRef.getLangOpts().CPlusPlus11) { Consumer.addKeywordResult("char16_t"); Consumer.addKeywordResult("char32_t"); Consumer.addKeywordResult("constexpr"); Consumer.addKeywordResult("decltype"); Consumer.addKeywordResult("thread_local"); } } if (SemaRef.getLangOpts().GNUMode) Consumer.addKeywordResult("typeof"); } else if (CCC.WantFunctionLikeCasts) { static const char *const CastableTypeSpecs[] = { "char", "double", "float", "int", "long", "short", "signed", "unsigned", "void" }; for (auto *kw : CastableTypeSpecs) Consumer.addKeywordResult(kw); } if (CCC.WantCXXNamedCasts && SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("const_cast"); Consumer.addKeywordResult("dynamic_cast"); Consumer.addKeywordResult("reinterpret_cast"); Consumer.addKeywordResult("static_cast"); } if (CCC.WantExpressionKeywords) { Consumer.addKeywordResult("sizeof"); if (SemaRef.getLangOpts().Bool || SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("false"); Consumer.addKeywordResult("true"); } if (SemaRef.getLangOpts().CPlusPlus) { static const char *const CXXExprs[] = { "delete", "new", "operator", "throw", "typeid" }; const unsigned NumCXXExprs = llvm::array_lengthof(CXXExprs); for (unsigned I = 0; I != NumCXXExprs; ++I) Consumer.addKeywordResult(CXXExprs[I]); if (isa(SemaRef.CurContext) && cast(SemaRef.CurContext)->isInstance()) Consumer.addKeywordResult("this"); if (SemaRef.getLangOpts().CPlusPlus11) { Consumer.addKeywordResult("alignof"); Consumer.addKeywordResult("nullptr"); } } if (SemaRef.getLangOpts().C11) { // FIXME: We should not suggest _Alignof if the alignof macro // is present. Consumer.addKeywordResult("_Alignof"); } } if (CCC.WantRemainingKeywords) { if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) { // Statements. static const char *const CStmts[] = { "do", "else", "for", "goto", "if", "return", "switch", "while" }; const unsigned NumCStmts = llvm::array_lengthof(CStmts); for (unsigned I = 0; I != NumCStmts; ++I) Consumer.addKeywordResult(CStmts[I]); if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("catch"); Consumer.addKeywordResult("try"); } if (S && S->getBreakParent()) Consumer.addKeywordResult("break"); if (S && S->getContinueParent()) Consumer.addKeywordResult("continue"); if (!SemaRef.getCurFunction()->SwitchStack.empty()) { Consumer.addKeywordResult("case"); Consumer.addKeywordResult("default"); } } else { if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("namespace"); Consumer.addKeywordResult("template"); } if (S && S->isClassScope()) { Consumer.addKeywordResult("explicit"); Consumer.addKeywordResult("friend"); Consumer.addKeywordResult("mutable"); Consumer.addKeywordResult("private"); Consumer.addKeywordResult("protected"); Consumer.addKeywordResult("public"); Consumer.addKeywordResult("virtual"); } } if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("using"); if (SemaRef.getLangOpts().CPlusPlus11) Consumer.addKeywordResult("static_assert"); } } } std::unique_ptr Sema::makeTypoCorrectionConsumer( const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery) { if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking || DisableTypoCorrection) return nullptr; // In Microsoft mode, don't perform typo correction in a template member // function dependent context because it interferes with the "lookup into // dependent bases of class templates" feature. if (getLangOpts().MSVCCompat && CurContext->isDependentContext() && isa(CurContext)) return nullptr; // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!Typo) return nullptr; // If the scope specifier itself was invalid, don't try to correct // typos. if (SS && SS->isInvalid()) return nullptr; // Never try to correct typos during any kind of code synthesis. if (!CodeSynthesisContexts.empty()) return nullptr; // Don't try to correct 'super'. if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier()) return nullptr; // Abort if typo correction already failed for this specific typo. IdentifierSourceLocations::iterator locs = TypoCorrectionFailures.find(Typo); if (locs != TypoCorrectionFailures.end() && locs->second.count(TypoName.getLoc())) return nullptr; // Don't try to correct the identifier "vector" when in AltiVec mode. // TODO: Figure out why typo correction misbehaves in this case, fix it, and // remove this workaround. if ((getLangOpts().AltiVec || getLangOpts().ZVector) && Typo->isStr("vector")) return nullptr; // Provide a stop gap for files that are just seriously broken. Trying // to correct all typos can turn into a HUGE performance penalty, causing // some files to take minutes to get rejected by the parser. unsigned Limit = getDiagnostics().getDiagnosticOptions().SpellCheckingLimit; if (Limit && TyposCorrected >= Limit) return nullptr; ++TyposCorrected; // If we're handling a missing symbol error, using modules, and the // special search all modules option is used, look for a missing import. if (ErrorRecovery && getLangOpts().Modules && getLangOpts().ModulesSearchAll) { // The following has the side effect of loading the missing module. getModuleLoader().lookupMissingImports(Typo->getName(), TypoName.getLocStart()); } CorrectionCandidateCallback &CCCRef = *CCC; auto Consumer = llvm::make_unique( *this, TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, EnteringContext); // Perform name lookup to find visible, similarly-named entities. bool IsUnqualifiedLookup = false; DeclContext *QualifiedDC = MemberContext; if (MemberContext) { LookupVisibleDecls(MemberContext, LookupKind, *Consumer); // Look in qualified interfaces. if (OPT) { for (auto *I : OPT->quals()) LookupVisibleDecls(I, LookupKind, *Consumer); } } else if (SS && SS->isSet()) { QualifiedDC = computeDeclContext(*SS, EnteringContext); if (!QualifiedDC) return nullptr; LookupVisibleDecls(QualifiedDC, LookupKind, *Consumer); } else { IsUnqualifiedLookup = true; } // Determine whether we are going to search in the various namespaces for // corrections. bool SearchNamespaces = getLangOpts().CPlusPlus && (IsUnqualifiedLookup || (SS && SS->isSet())); if (IsUnqualifiedLookup || SearchNamespaces) { // For unqualified lookup, look through all of the names that we have // seen in this translation unit. // FIXME: Re-add the ability to skip very unlikely potential corrections. for (const auto &I : Context.Idents) Consumer->FoundName(I.getKey()); // Walk through identifiers in external identifier sources. // FIXME: Re-add the ability to skip very unlikely potential corrections. if (IdentifierInfoLookup *External = Context.Idents.getExternalIdentifierLookup()) { std::unique_ptr Iter(External->getIdentifiers()); do { StringRef Name = Iter->Next(); if (Name.empty()) break; Consumer->FoundName(Name); } while (true); } } AddKeywordsToConsumer(*this, *Consumer, S, CCCRef, SS && SS->isNotEmpty()); // Build the NestedNameSpecifiers for the KnownNamespaces, if we're going // to search those namespaces. if (SearchNamespaces) { // Load any externally-known namespaces. if (ExternalSource && !LoadedExternalKnownNamespaces) { SmallVector ExternalKnownNamespaces; LoadedExternalKnownNamespaces = true; ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces); for (auto *N : ExternalKnownNamespaces) KnownNamespaces[N] = true; } Consumer->addNamespaces(KnownNamespaces); } return Consumer; } /// \brief Try to "correct" a typo in the source code by finding /// visible declarations whose names are similar to the name that was /// present in the source code. /// /// \param TypoName the \c DeclarationNameInfo structure that contains /// the name that was present in the source code along with its location. /// /// \param LookupKind the name-lookup criteria used to search for the name. /// /// \param S the scope in which name lookup occurs. /// /// \param SS the nested-name-specifier that precedes the name we're /// looking for, if present. /// /// \param CCC A CorrectionCandidateCallback object that provides further /// validation of typo correction candidates. It also provides flags for /// determining the set of keywords permitted. /// /// \param MemberContext if non-NULL, the context in which to look for /// a member access expression. /// /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// /// \param OPT when non-NULL, the search for visible declarations will /// also walk the protocols in the qualified interfaces of \p OPT. /// /// \returns a \c TypoCorrection containing the corrected name if the typo /// along with information such as the \c NamedDecl where the corrected name /// was declared, and any additional \c NestedNameSpecifier needed to access /// it (C++ only). The \c TypoCorrection is empty if there is no correction. TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool RecordFailure) { assert(CCC && "CorrectTypo requires a CorrectionCandidateCallback"); // Always let the ExternalSource have the first chance at correction, even // if we would otherwise have given up. if (ExternalSource) { if (TypoCorrection Correction = ExternalSource->CorrectTypo( TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT)) return Correction; } // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver; // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for // some instances of CTC_Unknown, while WantRemainingKeywords is true // for CTC_Unknown but not for CTC_ObjCMessageReceiver. bool ObjCMessageReceiver = CCC->WantObjCSuper && !CCC->WantRemainingKeywords; IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); auto Consumer = makeTypoCorrectionConsumer( TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, EnteringContext, OPT, Mode == CTK_ErrorRecovery); if (!Consumer) return TypoCorrection(); // If we haven't found anything, we're done. if (Consumer->empty()) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); // Make sure the best edit distance (prior to adding any namespace qualifiers) // is not more that about a third of the length of the typo's identifier. unsigned ED = Consumer->getBestEditDistance(true); unsigned TypoLen = Typo->getName().size(); if (ED > 0 && TypoLen / ED < 3) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); TypoCorrection BestTC = Consumer->getNextCorrection(); TypoCorrection SecondBestTC = Consumer->getNextCorrection(); if (!BestTC) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); ED = BestTC.getEditDistance(); if (TypoLen >= 3 && ED > 0 && TypoLen / ED < 3) { // If this was an unqualified lookup and we believe the callback // object wouldn't have filtered out possible corrections, note // that no correction was found. return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); } // If only a single name remains, return that result. if (!SecondBestTC || SecondBestTC.getEditDistance(false) > BestTC.getEditDistance(false)) { const TypoCorrection &Result = BestTC; // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. if (ED == 0 && Result.isKeyword()) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); TypoCorrection TC = Result; TC.setCorrectionRange(SS, TypoName); checkCorrectionVisibility(*this, TC); return TC; } else if (SecondBestTC && ObjCMessageReceiver) { // Prefer 'super' when we're completing in a message-receiver // context. if (BestTC.getCorrection().getAsString() != "super") { if (SecondBestTC.getCorrection().getAsString() == "super") BestTC = SecondBestTC; else if ((*Consumer)["super"].front().isKeyword()) BestTC = (*Consumer)["super"].front(); } // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. if (BestTC.getEditDistance() == 0 || BestTC.getCorrection().getAsString() != "super") return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); BestTC.setCorrectionRange(SS, TypoName); return BestTC; } // Record the failure's location if needed and return an empty correction. If // this was an unqualified lookup and we believe the callback object did not // filter out possible corrections, also cache the failure for the typo. return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure && !SecondBestTC); } /// \brief Try to "correct" a typo in the source code by finding /// visible declarations whose names are similar to the name that was /// present in the source code. /// /// \param TypoName the \c DeclarationNameInfo structure that contains /// the name that was present in the source code along with its location. /// /// \param LookupKind the name-lookup criteria used to search for the name. /// /// \param S the scope in which name lookup occurs. /// /// \param SS the nested-name-specifier that precedes the name we're /// looking for, if present. /// /// \param CCC A CorrectionCandidateCallback object that provides further /// validation of typo correction candidates. It also provides flags for /// determining the set of keywords permitted. /// /// \param TDG A TypoDiagnosticGenerator functor that will be used to print /// diagnostics when the actual typo correction is attempted. /// /// \param TRC A TypoRecoveryCallback functor that will be used to build an /// Expr from a typo correction candidate. /// /// \param MemberContext if non-NULL, the context in which to look for /// a member access expression. /// /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// /// \param OPT when non-NULL, the search for visible declarations will /// also walk the protocols in the qualified interfaces of \p OPT. /// /// \returns a new \c TypoExpr that will later be replaced in the AST with an /// Expr representing the result of performing typo correction, or nullptr if /// typo correction is not possible. If nullptr is returned, no diagnostics will /// be emitted and it is the responsibility of the caller to emit any that are /// needed. TypoExpr *Sema::CorrectTypoDelayed( const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT) { assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback"); auto Consumer = makeTypoCorrectionConsumer( TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, EnteringContext, OPT, Mode == CTK_ErrorRecovery); // Give the external sema source a chance to correct the typo. TypoCorrection ExternalTypo; if (ExternalSource && Consumer) { ExternalTypo = ExternalSource->CorrectTypo( TypoName, LookupKind, S, SS, *Consumer->getCorrectionValidator(), MemberContext, EnteringContext, OPT); if (ExternalTypo) Consumer->addCorrection(ExternalTypo); } if (!Consumer || Consumer->empty()) return nullptr; // Make sure the best edit distance (prior to adding any namespace qualifiers) // is not more that about a third of the length of the typo's identifier. unsigned ED = Consumer->getBestEditDistance(true); IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3) return nullptr; ExprEvalContexts.back().NumTypos++; return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC)); } void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { if (!CDecl) return; if (isKeyword()) CorrectionDecls.clear(); CorrectionDecls.push_back(CDecl); if (!CorrectionName) CorrectionName = CDecl->getDeclName(); } std::string TypoCorrection::getAsString(const LangOptions &LO) const { if (CorrectionNameSpec) { std::string tmpBuffer; llvm::raw_string_ostream PrefixOStream(tmpBuffer); CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO)); PrefixOStream << CorrectionName; return PrefixOStream.str(); } return CorrectionName.getAsString(); } bool CorrectionCandidateCallback::ValidateCandidate( const TypoCorrection &candidate) { if (!candidate.isResolved()) return true; if (candidate.isKeyword()) return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts || WantRemainingKeywords || WantObjCSuper; bool HasNonType = false; bool HasStaticMethod = false; bool HasNonStaticMethod = false; for (Decl *D : candidate) { if (FunctionTemplateDecl *FTD = dyn_cast(D)) D = FTD->getTemplatedDecl(); if (CXXMethodDecl *Method = dyn_cast(D)) { if (Method->isStatic()) HasStaticMethod = true; else HasNonStaticMethod = true; } if (!isa(D)) HasNonType = true; } if (IsAddressOfOperand && HasNonStaticMethod && !HasStaticMethod && !candidate.getCorrectionSpecifier()) return false; return WantTypeSpecifiers || HasNonType; } FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs, MemberExpr *ME) : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs), CurContext(SemaRef.CurContext), MemberFn(ME) { WantTypeSpecifiers = false; WantFunctionLikeCasts = SemaRef.getLangOpts().CPlusPlus && NumArgs == 1; WantRemainingKeywords = false; } bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) { if (!candidate.getCorrectionDecl()) return candidate.isKeyword(); for (auto *C : candidate) { FunctionDecl *FD = nullptr; NamedDecl *ND = C->getUnderlyingDecl(); if (FunctionTemplateDecl *FTD = dyn_cast(ND)) FD = FTD->getTemplatedDecl(); if (!HasExplicitTemplateArgs && !FD) { if (!(FD = dyn_cast(ND)) && isa(ND)) { // If the Decl is neither a function nor a template function, // determine if it is a pointer or reference to a function. If so, // check against the number of arguments expected for the pointee. QualType ValType = cast(ND)->getType(); if (ValType->isAnyPointerType() || ValType->isReferenceType()) ValType = ValType->getPointeeType(); if (const FunctionProtoType *FPT = ValType->getAs()) if (FPT->getNumParams() == NumArgs) return true; } } // Skip the current candidate if it is not a FunctionDecl or does not accept // the current number of arguments. if (!FD || !(FD->getNumParams() >= NumArgs && FD->getMinRequiredArguments() <= NumArgs)) continue; // If the current candidate is a non-static C++ method, skip the candidate // unless the method being corrected--or the current DeclContext, if the // function being corrected is not a method--is a method in the same class // or a descendent class of the candidate's parent class. if (CXXMethodDecl *MD = dyn_cast(FD)) { if (MemberFn || !MD->isStatic()) { CXXMethodDecl *CurMD = MemberFn ? dyn_cast_or_null(MemberFn->getMemberDecl()) : dyn_cast_or_null(CurContext); CXXRecordDecl *CurRD = CurMD ? CurMD->getParent()->getCanonicalDecl() : nullptr; CXXRecordDecl *RD = MD->getParent()->getCanonicalDecl(); if (!CurRD || (CurRD != RD && !CurRD->isDerivedFrom(RD))) continue; } } return true; } return false; } void Sema::diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, bool ErrorRecovery) { diagnoseTypo(Correction, TypoDiag, PDiag(diag::note_previous_decl), ErrorRecovery); } /// Find which declaration we should import to provide the definition of /// the given declaration. static NamedDecl *getDefinitionToImport(NamedDecl *D) { if (VarDecl *VD = dyn_cast(D)) return VD->getDefinition(); if (FunctionDecl *FD = dyn_cast(D)) return FD->getDefinition(); if (TagDecl *TD = dyn_cast(D)) return TD->getDefinition(); if (ObjCInterfaceDecl *ID = dyn_cast(D)) return ID->getDefinition(); if (ObjCProtocolDecl *PD = dyn_cast(D)) return PD->getDefinition(); if (TemplateDecl *TD = dyn_cast(D)) return getDefinitionToImport(TD->getTemplatedDecl()); return nullptr; } void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, MissingImportKind MIK, bool Recover) { assert(!isVisible(Decl) && "missing import for non-hidden decl?"); // Suggest importing a module providing the definition of this entity, if // possible. NamedDecl *Def = getDefinitionToImport(Decl); if (!Def) Def = Decl; Module *Owner = getOwningModule(Decl); assert(Owner && "definition of hidden declaration is not in a module"); llvm::SmallVector OwningModules; OwningModules.push_back(Owner); auto Merged = Context.getModulesWithMergedDefinition(Decl); OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end()); diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, MIK, Recover); } /// \brief Get a "quoted.h" or include path to use in a diagnostic /// suggesting the addition of a #include of the specified file. static std::string getIncludeStringForHeader(Preprocessor &PP, const FileEntry *E) { bool IsSystem; auto Path = PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics(E, &IsSystem); return (IsSystem ? '<' : '"') + Path + (IsSystem ? '>' : '"'); } void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, SourceLocation DeclLoc, ArrayRef Modules, MissingImportKind MIK, bool Recover) { assert(!Modules.empty()); if (Modules.size() > 1) { std::string ModuleList; unsigned N = 0; for (Module *M : Modules) { ModuleList += "\n "; if (++N == 5 && N != Modules.size()) { ModuleList += "[...]"; break; } ModuleList += M->getFullModuleName(); } Diag(UseLoc, diag::err_module_unimported_use_multiple) << (int)MIK << Decl << ModuleList; } else if (const FileEntry *E = PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, DeclLoc)) { // The right way to make the declaration visible is to include a header; // suggest doing so. // // FIXME: Find a smart place to suggest inserting a #include, and add // a FixItHint there. Diag(UseLoc, diag::err_module_unimported_use_header) << (int)MIK << Decl << Modules[0]->getFullModuleName() << getIncludeStringForHeader(PP, E); } else { // FIXME: Add a FixItHint that imports the corresponding module. Diag(UseLoc, diag::err_module_unimported_use) << (int)MIK << Decl << Modules[0]->getFullModuleName(); } unsigned DiagID; switch (MIK) { case MissingImportKind::Declaration: DiagID = diag::note_previous_declaration; break; case MissingImportKind::Definition: DiagID = diag::note_previous_definition; break; case MissingImportKind::DefaultArgument: DiagID = diag::note_default_argument_declared_here; break; case MissingImportKind::ExplicitSpecialization: DiagID = diag::note_explicit_specialization_declared_here; break; case MissingImportKind::PartialSpecialization: DiagID = diag::note_partial_specialization_declared_here; break; } Diag(DeclLoc, DiagID); // Try to recover by implicitly importing this module. if (Recover) createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]); } /// \brief Diagnose a successfully-corrected typo. Separated from the correction /// itself to allow external validation of the result, etc. /// /// \param Correction The result of performing typo correction. /// \param TypoDiag The diagnostic to produce. This will have the corrected /// string added to it (and usually also a fixit). /// \param PrevNote A note to use when indicating the location of the entity to /// which we are correcting. Will have the correction string added to it. /// \param ErrorRecovery If \c true (the default), the caller is going to /// recover from the typo as if the corrected string had been typed. /// In this case, \c PDiag must be an error, and we will attach a fixit /// to it. void Sema::diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, const PartialDiagnostic &PrevNote, bool ErrorRecovery) { std::string CorrectedStr = Correction.getAsString(getLangOpts()); std::string CorrectedQuotedStr = Correction.getQuoted(getLangOpts()); FixItHint FixTypo = FixItHint::CreateReplacement( Correction.getCorrectionRange(), CorrectedStr); // Maybe we're just missing a module import. if (Correction.requiresImport()) { NamedDecl *Decl = Correction.getFoundDecl(); assert(Decl && "import required but no declaration to import"); diagnoseMissingImport(Correction.getCorrectionRange().getBegin(), Decl, MissingImportKind::Declaration, ErrorRecovery); return; } Diag(Correction.getCorrectionRange().getBegin(), TypoDiag) << CorrectedQuotedStr << (ErrorRecovery ? FixTypo : FixItHint()); NamedDecl *ChosenDecl = Correction.isKeyword() ? nullptr : Correction.getFoundDecl(); if (PrevNote.getDiagID() && ChosenDecl) Diag(ChosenDecl->getLocation(), PrevNote) << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo); // Add any extra diagnostics. for (const PartialDiagnostic &PD : Correction.getExtraDiagnostics()) Diag(Correction.getCorrectionRange().getBegin(), PD); } TypoExpr *Sema::createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC) { assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer"); auto TE = new (Context) TypoExpr(Context.DependentTy); auto &State = DelayedTypos[TE]; State.Consumer = std::move(TCC); State.DiagHandler = std::move(TDG); State.RecoveryHandler = std::move(TRC); return TE; } const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const { auto Entry = DelayedTypos.find(TE); assert(Entry != DelayedTypos.end() && "Failed to get the state for a TypoExpr!"); return Entry->second; } void Sema::clearDelayedTypo(TypoExpr *TE) { DelayedTypos.erase(TE); } void Sema::ActOnPragmaDump(Scope *S, SourceLocation IILoc, IdentifierInfo *II) { DeclarationNameInfo Name(II, IILoc); LookupResult R(*this, Name, LookupAnyName, Sema::NotForRedeclaration); R.suppressDiagnostics(); R.setHideTags(false); LookupName(R, S); R.dump(); } Index: vendor/clang/dist/lib/Serialization/ASTReader.cpp =================================================================== --- vendor/clang/dist/lib/Serialization/ASTReader.cpp (revision 318415) +++ vendor/clang/dist/lib/Serialization/ASTReader.cpp (revision 318416) @@ -1,9878 +1,9851 @@ //===-- ASTReader.cpp - AST File Reader -----------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the ASTReader class, which reads AST files. // //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTReader.h" #include "ASTCommon.h" #include "ASTReaderInternals.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/ODRHash.h" #include "clang/AST/RawCommentList.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/CommentOptions.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/MemoryBufferCache.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Sanitizers.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TokenKinds.h" #include "clang/Basic/Version.h" #include "clang/Basic/VersionTuple.h" #include "clang/Frontend/PCHContainerOperations.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Weak.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/ModuleManager.h" #include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace clang; using namespace clang::serialization; using namespace clang::serialization::reader; using llvm::BitstreamCursor; //===----------------------------------------------------------------------===// // ChainedASTReaderListener implementation //===----------------------------------------------------------------------===// bool ChainedASTReaderListener::ReadFullVersionInformation(StringRef FullVersion) { return First->ReadFullVersionInformation(FullVersion) || Second->ReadFullVersionInformation(FullVersion); } void ChainedASTReaderListener::ReadModuleName(StringRef ModuleName) { First->ReadModuleName(ModuleName); Second->ReadModuleName(ModuleName); } void ChainedASTReaderListener::ReadModuleMapFile(StringRef ModuleMapPath) { First->ReadModuleMapFile(ModuleMapPath); Second->ReadModuleMapFile(ModuleMapPath); } bool ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) { return First->ReadLanguageOptions(LangOpts, Complain, AllowCompatibleDifferences) || Second->ReadLanguageOptions(LangOpts, Complain, AllowCompatibleDifferences); } bool ChainedASTReaderListener::ReadTargetOptions( const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) { return First->ReadTargetOptions(TargetOpts, Complain, AllowCompatibleDifferences) || Second->ReadTargetOptions(TargetOpts, Complain, AllowCompatibleDifferences); } bool ChainedASTReaderListener::ReadDiagnosticOptions( IntrusiveRefCntPtr DiagOpts, bool Complain) { return First->ReadDiagnosticOptions(DiagOpts, Complain) || Second->ReadDiagnosticOptions(DiagOpts, Complain); } bool ChainedASTReaderListener::ReadFileSystemOptions(const FileSystemOptions &FSOpts, bool Complain) { return First->ReadFileSystemOptions(FSOpts, Complain) || Second->ReadFileSystemOptions(FSOpts, Complain); } bool ChainedASTReaderListener::ReadHeaderSearchOptions( const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) { return First->ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, Complain) || Second->ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, Complain); } bool ChainedASTReaderListener::ReadPreprocessorOptions( const PreprocessorOptions &PPOpts, bool Complain, std::string &SuggestedPredefines) { return First->ReadPreprocessorOptions(PPOpts, Complain, SuggestedPredefines) || Second->ReadPreprocessorOptions(PPOpts, Complain, SuggestedPredefines); } void ChainedASTReaderListener::ReadCounter(const serialization::ModuleFile &M, unsigned Value) { First->ReadCounter(M, Value); Second->ReadCounter(M, Value); } bool ChainedASTReaderListener::needsInputFileVisitation() { return First->needsInputFileVisitation() || Second->needsInputFileVisitation(); } bool ChainedASTReaderListener::needsSystemInputFileVisitation() { return First->needsSystemInputFileVisitation() || Second->needsSystemInputFileVisitation(); } void ChainedASTReaderListener::visitModuleFile(StringRef Filename, ModuleKind Kind) { First->visitModuleFile(Filename, Kind); Second->visitModuleFile(Filename, Kind); } bool ChainedASTReaderListener::visitInputFile(StringRef Filename, bool isSystem, bool isOverridden, bool isExplicitModule) { bool Continue = false; if (First->needsInputFileVisitation() && (!isSystem || First->needsSystemInputFileVisitation())) Continue |= First->visitInputFile(Filename, isSystem, isOverridden, isExplicitModule); if (Second->needsInputFileVisitation() && (!isSystem || Second->needsSystemInputFileVisitation())) Continue |= Second->visitInputFile(Filename, isSystem, isOverridden, isExplicitModule); return Continue; } void ChainedASTReaderListener::readModuleFileExtension( const ModuleFileExtensionMetadata &Metadata) { First->readModuleFileExtension(Metadata); Second->readModuleFileExtension(Metadata); } //===----------------------------------------------------------------------===// // PCH validator implementation //===----------------------------------------------------------------------===// ASTReaderListener::~ASTReaderListener() {} /// \brief Compare the given set of language options against an existing set of /// language options. /// /// \param Diags If non-NULL, diagnostics will be emitted via this engine. /// \param AllowCompatibleDifferences If true, differences between compatible /// language options will be permitted. /// /// \returns true if the languagae options mis-match, false otherwise. static bool checkLanguageOptions(const LangOptions &LangOpts, const LangOptions &ExistingLangOpts, DiagnosticsEngine *Diags, bool AllowCompatibleDifferences = true) { #define LANGOPT(Name, Bits, Default, Description) \ if (ExistingLangOpts.Name != LangOpts.Name) { \ if (Diags) \ Diags->Report(diag::err_pch_langopt_mismatch) \ << Description << LangOpts.Name << ExistingLangOpts.Name; \ return true; \ } #define VALUE_LANGOPT(Name, Bits, Default, Description) \ if (ExistingLangOpts.Name != LangOpts.Name) { \ if (Diags) \ Diags->Report(diag::err_pch_langopt_value_mismatch) \ << Description; \ return true; \ } #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \ if (Diags) \ Diags->Report(diag::err_pch_langopt_value_mismatch) \ << Description; \ return true; \ } #define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \ if (!AllowCompatibleDifferences) \ LANGOPT(Name, Bits, Default, Description) #define COMPATIBLE_ENUM_LANGOPT(Name, Bits, Default, Description) \ if (!AllowCompatibleDifferences) \ ENUM_LANGOPT(Name, Bits, Default, Description) #define COMPATIBLE_VALUE_LANGOPT(Name, Bits, Default, Description) \ if (!AllowCompatibleDifferences) \ VALUE_LANGOPT(Name, Bits, Default, Description) #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #define BENIGN_VALUE_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" if (ExistingLangOpts.ModuleFeatures != LangOpts.ModuleFeatures) { if (Diags) Diags->Report(diag::err_pch_langopt_value_mismatch) << "module features"; return true; } if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) { if (Diags) Diags->Report(diag::err_pch_langopt_value_mismatch) << "target Objective-C runtime"; return true; } if (ExistingLangOpts.CommentOpts.BlockCommandNames != LangOpts.CommentOpts.BlockCommandNames) { if (Diags) Diags->Report(diag::err_pch_langopt_value_mismatch) << "block command names"; return true; } return false; } /// \brief Compare the given set of target options against an existing set of /// target options. /// /// \param Diags If non-NULL, diagnostics will be emitted via this engine. /// /// \returns true if the target options mis-match, false otherwise. static bool checkTargetOptions(const TargetOptions &TargetOpts, const TargetOptions &ExistingTargetOpts, DiagnosticsEngine *Diags, bool AllowCompatibleDifferences = true) { #define CHECK_TARGET_OPT(Field, Name) \ if (TargetOpts.Field != ExistingTargetOpts.Field) { \ if (Diags) \ Diags->Report(diag::err_pch_targetopt_mismatch) \ << Name << TargetOpts.Field << ExistingTargetOpts.Field; \ return true; \ } // The triple and ABI must match exactly. CHECK_TARGET_OPT(Triple, "target"); CHECK_TARGET_OPT(ABI, "target ABI"); // We can tolerate different CPUs in many cases, notably when one CPU // supports a strict superset of another. When allowing compatible // differences skip this check. if (!AllowCompatibleDifferences) CHECK_TARGET_OPT(CPU, "target CPU"); #undef CHECK_TARGET_OPT // Compare feature sets. SmallVector ExistingFeatures( ExistingTargetOpts.FeaturesAsWritten.begin(), ExistingTargetOpts.FeaturesAsWritten.end()); SmallVector ReadFeatures(TargetOpts.FeaturesAsWritten.begin(), TargetOpts.FeaturesAsWritten.end()); std::sort(ExistingFeatures.begin(), ExistingFeatures.end()); std::sort(ReadFeatures.begin(), ReadFeatures.end()); // We compute the set difference in both directions explicitly so that we can // diagnose the differences differently. SmallVector UnmatchedExistingFeatures, UnmatchedReadFeatures; std::set_difference( ExistingFeatures.begin(), ExistingFeatures.end(), ReadFeatures.begin(), ReadFeatures.end(), std::back_inserter(UnmatchedExistingFeatures)); std::set_difference(ReadFeatures.begin(), ReadFeatures.end(), ExistingFeatures.begin(), ExistingFeatures.end(), std::back_inserter(UnmatchedReadFeatures)); // If we are allowing compatible differences and the read feature set is // a strict subset of the existing feature set, there is nothing to diagnose. if (AllowCompatibleDifferences && UnmatchedReadFeatures.empty()) return false; if (Diags) { for (StringRef Feature : UnmatchedReadFeatures) Diags->Report(diag::err_pch_targetopt_feature_mismatch) << /* is-existing-feature */ false << Feature; for (StringRef Feature : UnmatchedExistingFeatures) Diags->Report(diag::err_pch_targetopt_feature_mismatch) << /* is-existing-feature */ true << Feature; } return !UnmatchedReadFeatures.empty() || !UnmatchedExistingFeatures.empty(); } bool PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) { const LangOptions &ExistingLangOpts = PP.getLangOpts(); return checkLanguageOptions(LangOpts, ExistingLangOpts, Complain ? &Reader.Diags : nullptr, AllowCompatibleDifferences); } bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) { const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts(); return checkTargetOptions(TargetOpts, ExistingTargetOpts, Complain ? &Reader.Diags : nullptr, AllowCompatibleDifferences); } namespace { typedef llvm::StringMap > MacroDefinitionsMap; typedef llvm::DenseMap > DeclsMap; } // end anonymous namespace static bool checkDiagnosticGroupMappings(DiagnosticsEngine &StoredDiags, DiagnosticsEngine &Diags, bool Complain) { typedef DiagnosticsEngine::Level Level; // Check current mappings for new -Werror mappings, and the stored mappings // for cases that were explicitly mapped to *not* be errors that are now // errors because of options like -Werror. DiagnosticsEngine *MappingSources[] = { &Diags, &StoredDiags }; for (DiagnosticsEngine *MappingSource : MappingSources) { for (auto DiagIDMappingPair : MappingSource->getDiagnosticMappings()) { diag::kind DiagID = DiagIDMappingPair.first; Level CurLevel = Diags.getDiagnosticLevel(DiagID, SourceLocation()); if (CurLevel < DiagnosticsEngine::Error) continue; // not significant Level StoredLevel = StoredDiags.getDiagnosticLevel(DiagID, SourceLocation()); if (StoredLevel < DiagnosticsEngine::Error) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror=" + Diags.getDiagnosticIDs()->getWarningOptionForDiag(DiagID).str(); return true; } } } return false; } static bool isExtHandlingFromDiagsError(DiagnosticsEngine &Diags) { diag::Severity Ext = Diags.getExtensionHandlingBehavior(); if (Ext == diag::Severity::Warning && Diags.getWarningsAsErrors()) return true; return Ext >= diag::Severity::Error; } static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags, DiagnosticsEngine &Diags, bool IsSystem, bool Complain) { // Top-level options if (IsSystem) { if (Diags.getSuppressSystemWarnings()) return false; // If -Wsystem-headers was not enabled before, be conservative if (StoredDiags.getSuppressSystemWarnings()) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-Wsystem-headers"; return true; } } if (Diags.getWarningsAsErrors() && !StoredDiags.getWarningsAsErrors()) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror"; return true; } if (Diags.getWarningsAsErrors() && Diags.getEnableAllWarnings() && !StoredDiags.getEnableAllWarnings()) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-Weverything -Werror"; return true; } if (isExtHandlingFromDiagsError(Diags) && !isExtHandlingFromDiagsError(StoredDiags)) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-pedantic-errors"; return true; } return checkDiagnosticGroupMappings(StoredDiags, Diags, Complain); } /// Return the top import module if it is implicit, nullptr otherwise. static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr, Preprocessor &PP) { // If the original import came from a file explicitly generated by the user, // don't check the diagnostic mappings. // FIXME: currently this is approximated by checking whether this is not a // module import of an implicitly-loaded module file. // Note: ModuleMgr.rbegin() may not be the current module, but it must be in // the transitive closure of its imports, since unrelated modules cannot be // imported until after this module finishes validation. ModuleFile *TopImport = &*ModuleMgr.rbegin(); while (!TopImport->ImportedBy.empty()) TopImport = TopImport->ImportedBy[0]; if (TopImport->Kind != MK_ImplicitModule) return nullptr; StringRef ModuleName = TopImport->ModuleName; assert(!ModuleName.empty() && "diagnostic options read before module name"); Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName); assert(M && "missing module"); return M; } bool PCHValidator::ReadDiagnosticOptions( IntrusiveRefCntPtr DiagOpts, bool Complain) { DiagnosticsEngine &ExistingDiags = PP.getDiagnostics(); IntrusiveRefCntPtr DiagIDs(ExistingDiags.getDiagnosticIDs()); IntrusiveRefCntPtr Diags( new DiagnosticsEngine(DiagIDs, DiagOpts.get())); // This should never fail, because we would have processed these options // before writing them to an ASTFile. ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false); ModuleManager &ModuleMgr = Reader.getModuleManager(); assert(ModuleMgr.size() >= 1 && "what ASTFile is this then"); Module *TopM = getTopImportImplicitModule(ModuleMgr, PP); if (!TopM) return false; // FIXME: if the diagnostics are incompatible, save a DiagnosticOptions that // contains the union of their flags. return checkDiagnosticMappings(*Diags, ExistingDiags, TopM->IsSystem, Complain); } /// \brief Collect the macro definitions provided by the given preprocessor /// options. static void collectMacroDefinitions(const PreprocessorOptions &PPOpts, MacroDefinitionsMap &Macros, SmallVectorImpl *MacroNames = nullptr) { for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) { StringRef Macro = PPOpts.Macros[I].first; bool IsUndef = PPOpts.Macros[I].second; std::pair MacroPair = Macro.split('='); StringRef MacroName = MacroPair.first; StringRef MacroBody = MacroPair.second; // For an #undef'd macro, we only care about the name. if (IsUndef) { if (MacroNames && !Macros.count(MacroName)) MacroNames->push_back(MacroName); Macros[MacroName] = std::make_pair("", true); continue; } // For a #define'd macro, figure out the actual definition. if (MacroName.size() == Macro.size()) MacroBody = "1"; else { // Note: GCC drops anything following an end-of-line character. StringRef::size_type End = MacroBody.find_first_of("\n\r"); MacroBody = MacroBody.substr(0, End); } if (MacroNames && !Macros.count(MacroName)) MacroNames->push_back(MacroName); Macros[MacroName] = std::make_pair(MacroBody, false); } } /// \brief Check the preprocessor options deserialized from the control block /// against the preprocessor options in an existing preprocessor. /// /// \param Diags If non-null, produce diagnostics for any mismatches incurred. /// \param Validate If true, validate preprocessor options. If false, allow /// macros defined by \p ExistingPPOpts to override those defined by /// \p PPOpts in SuggestedPredefines. static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, const PreprocessorOptions &ExistingPPOpts, DiagnosticsEngine *Diags, FileManager &FileMgr, std::string &SuggestedPredefines, const LangOptions &LangOpts, bool Validate = true) { // Check macro definitions. MacroDefinitionsMap ASTFileMacros; collectMacroDefinitions(PPOpts, ASTFileMacros); MacroDefinitionsMap ExistingMacros; SmallVector ExistingMacroNames; collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames); for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) { // Dig out the macro definition in the existing preprocessor options. StringRef MacroName = ExistingMacroNames[I]; std::pair Existing = ExistingMacros[MacroName]; // Check whether we know anything about this macro name or not. llvm::StringMap >::iterator Known = ASTFileMacros.find(MacroName); if (!Validate || Known == ASTFileMacros.end()) { // FIXME: Check whether this identifier was referenced anywhere in the // AST file. If so, we should reject the AST file. Unfortunately, this // information isn't in the control block. What shall we do about it? if (Existing.second) { SuggestedPredefines += "#undef "; SuggestedPredefines += MacroName.str(); SuggestedPredefines += '\n'; } else { SuggestedPredefines += "#define "; SuggestedPredefines += MacroName.str(); SuggestedPredefines += ' '; SuggestedPredefines += Existing.first.str(); SuggestedPredefines += '\n'; } continue; } // If the macro was defined in one but undef'd in the other, we have a // conflict. if (Existing.second != Known->second.second) { if (Diags) { Diags->Report(diag::err_pch_macro_def_undef) << MacroName << Known->second.second; } return true; } // If the macro was #undef'd in both, or if the macro bodies are identical, // it's fine. if (Existing.second || Existing.first == Known->second.first) continue; // The macro bodies differ; complain. if (Diags) { Diags->Report(diag::err_pch_macro_def_conflict) << MacroName << Known->second.first << Existing.first; } return true; } // Check whether we're using predefines. if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines && Validate) { if (Diags) { Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines; } return true; } // Detailed record is important since it is used for the module cache hash. if (LangOpts.Modules && PPOpts.DetailedRecord != ExistingPPOpts.DetailedRecord && Validate) { if (Diags) { Diags->Report(diag::err_pch_pp_detailed_record) << PPOpts.DetailedRecord; } return true; } // Compute the #include and #include_macros lines we need. for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) { StringRef File = ExistingPPOpts.Includes[I]; if (File == ExistingPPOpts.ImplicitPCHInclude) continue; if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File) != PPOpts.Includes.end()) continue; SuggestedPredefines += "#include \""; SuggestedPredefines += File; SuggestedPredefines += "\"\n"; } for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) { StringRef File = ExistingPPOpts.MacroIncludes[I]; if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(), File) != PPOpts.MacroIncludes.end()) continue; SuggestedPredefines += "#__include_macros \""; SuggestedPredefines += File; SuggestedPredefines += "\"\n##\n"; } return false; } bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain, std::string &SuggestedPredefines) { const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts(); return checkPreprocessorOptions(PPOpts, ExistingPPOpts, Complain? &Reader.Diags : nullptr, PP.getFileManager(), SuggestedPredefines, PP.getLangOpts()); } bool SimpleASTReaderListener::ReadPreprocessorOptions( const PreprocessorOptions &PPOpts, bool Complain, std::string &SuggestedPredefines) { return checkPreprocessorOptions(PPOpts, PP.getPreprocessorOpts(), nullptr, PP.getFileManager(), SuggestedPredefines, PP.getLangOpts(), false); } /// Check the header search options deserialized from the control block /// against the header search options in an existing preprocessor. /// /// \param Diags If non-null, produce diagnostics for any mismatches incurred. static bool checkHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, StringRef ExistingModuleCachePath, DiagnosticsEngine *Diags, const LangOptions &LangOpts) { if (LangOpts.Modules) { if (SpecificModuleCachePath != ExistingModuleCachePath) { if (Diags) Diags->Report(diag::err_pch_modulecache_mismatch) << SpecificModuleCachePath << ExistingModuleCachePath; return true; } } return false; } bool PCHValidator::ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) { return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath, PP.getHeaderSearchInfo().getModuleCachePath(), Complain ? &Reader.Diags : nullptr, PP.getLangOpts()); } void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) { PP.setCounterValue(Value); } //===----------------------------------------------------------------------===// // AST reader implementation //===----------------------------------------------------------------------===// void ASTReader::setDeserializationListener(ASTDeserializationListener *Listener, bool TakeOwnership) { DeserializationListener = Listener; OwnsDeserializationListener = TakeOwnership; } unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) { return serialization::ComputeHash(Sel); } std::pair ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { using namespace llvm::support; unsigned KeyLen = endian::readNext(d); unsigned DataLen = endian::readNext(d); return std::make_pair(KeyLen, DataLen); } ASTSelectorLookupTrait::internal_key_type ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) { using namespace llvm::support; SelectorTable &SelTable = Reader.getContext().Selectors; unsigned N = endian::readNext(d); IdentifierInfo *FirstII = Reader.getLocalIdentifier( F, endian::readNext(d)); if (N == 0) return SelTable.getNullarySelector(FirstII); else if (N == 1) return SelTable.getUnarySelector(FirstII); SmallVector Args; Args.push_back(FirstII); for (unsigned I = 1; I != N; ++I) Args.push_back(Reader.getLocalIdentifier( F, endian::readNext(d))); return SelTable.getSelector(N, Args.data()); } ASTSelectorLookupTrait::data_type ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, unsigned DataLen) { using namespace llvm::support; data_type Result; Result.ID = Reader.getGlobalSelectorID( F, endian::readNext(d)); unsigned FullInstanceBits = endian::readNext(d); unsigned FullFactoryBits = endian::readNext(d); Result.InstanceBits = FullInstanceBits & 0x3; Result.InstanceHasMoreThanOneDecl = (FullInstanceBits >> 2) & 0x1; Result.FactoryBits = FullFactoryBits & 0x3; Result.FactoryHasMoreThanOneDecl = (FullFactoryBits >> 2) & 0x1; unsigned NumInstanceMethods = FullInstanceBits >> 3; unsigned NumFactoryMethods = FullFactoryBits >> 3; // Load instance methods for (unsigned I = 0; I != NumInstanceMethods; ++I) { if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs( F, endian::readNext(d))) Result.Instance.push_back(Method); } // Load factory methods for (unsigned I = 0; I != NumFactoryMethods; ++I) { if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs( F, endian::readNext(d))) Result.Factory.push_back(Method); } return Result; } unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) { return llvm::HashString(a); } std::pair ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) { using namespace llvm::support; unsigned DataLen = endian::readNext(d); unsigned KeyLen = endian::readNext(d); return std::make_pair(KeyLen, DataLen); } ASTIdentifierLookupTraitBase::internal_key_type ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) { assert(n >= 2 && d[n-1] == '\0'); return StringRef((const char*) d, n-1); } /// \brief Whether the given identifier is "interesting". static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II, bool IsModule) { return II.hadMacroDefinition() || II.isPoisoned() || (IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) || II.hasRevertedTokenIDToIdentifier() || (!(IsModule && Reader.getContext().getLangOpts().CPlusPlus) && II.getFETokenInfo()); } static bool readBit(unsigned &Bits) { bool Value = Bits & 0x1; Bits >>= 1; return Value; } IdentID ASTIdentifierLookupTrait::ReadIdentifierID(const unsigned char *d) { using namespace llvm::support; unsigned RawID = endian::readNext(d); return Reader.getGlobalIdentifierID(F, RawID >> 1); } static void markIdentifierFromAST(ASTReader &Reader, IdentifierInfo &II) { if (!II.isFromAST()) { II.setIsFromAST(); bool IsModule = Reader.getPreprocessor().getCurrentModule() != nullptr; if (isInterestingIdentifier(Reader, II, IsModule)) II.setChangedSinceDeserialization(); } } IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, const unsigned char* d, unsigned DataLen) { using namespace llvm::support; unsigned RawID = endian::readNext(d); bool IsInteresting = RawID & 0x01; // Wipe out the "is interesting" bit. RawID = RawID >> 1; // Build the IdentifierInfo and link the identifier ID with it. IdentifierInfo *II = KnownII; if (!II) { II = &Reader.getIdentifierTable().getOwn(k); KnownII = II; } markIdentifierFromAST(Reader, *II); Reader.markIdentifierUpToDate(II); IdentID ID = Reader.getGlobalIdentifierID(F, RawID); if (!IsInteresting) { // For uninteresting identifiers, there's nothing else to do. Just notify // the reader that we've finished loading this identifier. Reader.SetIdentifierInfo(ID, II); return II; } unsigned ObjCOrBuiltinID = endian::readNext(d); unsigned Bits = endian::readNext(d); bool CPlusPlusOperatorKeyword = readBit(Bits); bool HasRevertedTokenIDToIdentifier = readBit(Bits); bool HasRevertedBuiltin = readBit(Bits); bool Poisoned = readBit(Bits); bool ExtensionToken = readBit(Bits); bool HadMacroDefinition = readBit(Bits); assert(Bits == 0 && "Extra bits in the identifier?"); DataLen -= 8; // Set or check the various bits in the IdentifierInfo structure. // Token IDs are read-only. if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier) II->revertTokenIDToIdentifier(); if (!F.isModule()) II->setObjCOrBuiltinID(ObjCOrBuiltinID); else if (HasRevertedBuiltin && II->getBuiltinID()) { II->revertBuiltin(); assert((II->hasRevertedBuiltin() || II->getObjCOrBuiltinID() == ObjCOrBuiltinID) && "Incorrect ObjC keyword or builtin ID"); } assert(II->isExtensionToken() == ExtensionToken && "Incorrect extension token flag"); (void)ExtensionToken; if (Poisoned) II->setIsPoisoned(true); assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && "Incorrect C++ operator keyword flag"); (void)CPlusPlusOperatorKeyword; // If this identifier is a macro, deserialize the macro // definition. if (HadMacroDefinition) { uint32_t MacroDirectivesOffset = endian::readNext(d); DataLen -= 4; Reader.addPendingMacro(II, &F, MacroDirectivesOffset); } Reader.SetIdentifierInfo(ID, II); // Read all of the declarations visible at global scope with this // name. if (DataLen > 0) { SmallVector DeclIDs; for (; DataLen > 0; DataLen -= 4) DeclIDs.push_back(Reader.getGlobalDeclID( F, endian::readNext(d))); Reader.SetGloballyVisibleDecls(II, DeclIDs); } return II; } DeclarationNameKey::DeclarationNameKey(DeclarationName Name) : Kind(Name.getNameKind()) { switch (Kind) { case DeclarationName::Identifier: Data = (uint64_t)Name.getAsIdentifierInfo(); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); break; case DeclarationName::CXXOperatorName: Data = Name.getCXXOverloadedOperator(); break; case DeclarationName::CXXLiteralOperatorName: Data = (uint64_t)Name.getCXXLiteralIdentifier(); break; case DeclarationName::CXXDeductionGuideName: Data = (uint64_t)Name.getCXXDeductionGuideTemplate() ->getDeclName().getAsIdentifierInfo(); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: Data = 0; break; } } unsigned DeclarationNameKey::getHash() const { llvm::FoldingSetNodeID ID; ID.AddInteger(Kind); switch (Kind) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXDeductionGuideName: ID.AddString(((IdentifierInfo*)Data)->getName()); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: ID.AddInteger(serialization::ComputeHash(Selector(Data))); break; case DeclarationName::CXXOperatorName: ID.AddInteger((OverloadedOperatorKind)Data); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: break; } return ID.ComputeHash(); } ModuleFile * ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) { using namespace llvm::support; uint32_t ModuleFileID = endian::readNext(d); return Reader.getLocalModuleFile(F, ModuleFileID); } std::pair ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char *&d) { using namespace llvm::support; unsigned KeyLen = endian::readNext(d); unsigned DataLen = endian::readNext(d); return std::make_pair(KeyLen, DataLen); } ASTDeclContextNameLookupTrait::internal_key_type ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) { using namespace llvm::support; auto Kind = (DeclarationName::NameKind)*d++; uint64_t Data; switch (Kind) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXDeductionGuideName: Data = (uint64_t)Reader.getLocalIdentifier( F, endian::readNext(d)); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: Data = (uint64_t)Reader.getLocalSelector( F, endian::readNext( d)).getAsOpaquePtr(); break; case DeclarationName::CXXOperatorName: Data = *d++; // OverloadedOperatorKind break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: Data = 0; break; } return DeclarationNameKey(Kind, Data); } void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen, data_type_builder &Val) { using namespace llvm::support; for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) { uint32_t LocalID = endian::readNext(d); Val.insert(Reader.getGlobalDeclID(F, LocalID)); } } bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, BitstreamCursor &Cursor, uint64_t Offset, DeclContext *DC) { assert(Offset != 0); SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(Offset); RecordData Record; StringRef Blob; unsigned Code = Cursor.ReadCode(); unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); if (RecCode != DECL_CONTEXT_LEXICAL) { Error("Expected lexical block"); return true; } assert(!isa(DC) && "expected a TU_UPDATE_LEXICAL record for TU"); // If we are handling a C++ class template instantiation, we can see multiple // lexical updates for the same record. It's important that we select only one // of them, so that field numbering works properly. Just pick the first one we // see. auto &Lex = LexicalDecls[DC]; if (!Lex.first) { Lex = std::make_pair( &M, llvm::makeArrayRef( reinterpret_cast( Blob.data()), Blob.size() / 4)); } DC->setHasExternalLexicalStorage(true); return false; } bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, BitstreamCursor &Cursor, uint64_t Offset, DeclID ID) { assert(Offset != 0); SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(Offset); RecordData Record; StringRef Blob; unsigned Code = Cursor.ReadCode(); unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); if (RecCode != DECL_CONTEXT_VISIBLE) { Error("Expected visible lookup table block"); return true; } // We can't safely determine the primary context yet, so delay attaching the // lookup table until we're done with recursive deserialization. auto *Data = (const unsigned char*)Blob.data(); PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data}); return false; } void ASTReader::Error(StringRef Msg) const { Error(diag::err_fe_pch_malformed, Msg); if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight() && !PP.getHeaderSearchInfo().getModuleCachePath().empty()) { Diag(diag::note_module_cache_path) << PP.getHeaderSearchInfo().getModuleCachePath(); } } void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2) const { if (Diags.isDiagnosticInFlight()) Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); else Diag(DiagID) << Arg1 << Arg2; } //===----------------------------------------------------------------------===// // Source Manager Deserialization //===----------------------------------------------------------------------===// /// \brief Read the line table in the source manager block. /// \returns true if there was an error. bool ASTReader::ParseLineTable(ModuleFile &F, const RecordData &Record) { unsigned Idx = 0; LineTableInfo &LineTable = SourceMgr.getLineTable(); // Parse the file names std::map FileIDs; for (unsigned I = 0; Record[Idx]; ++I) { // Extract the file name auto Filename = ReadPath(F, Record, Idx); FileIDs[I] = LineTable.getLineTableFilenameID(Filename); } ++Idx; // Parse the line entries std::vector Entries; while (Idx < Record.size()) { int FID = Record[Idx++]; assert(FID >= 0 && "Serialized line entries for non-local file."); // Remap FileID from 1-based old view. FID += F.SLocEntryBaseID - 1; // Extract the line entries unsigned NumEntries = Record[Idx++]; assert(NumEntries && "no line entries for file ID"); Entries.clear(); Entries.reserve(NumEntries); for (unsigned I = 0; I != NumEntries; ++I) { unsigned FileOffset = Record[Idx++]; unsigned LineNo = Record[Idx++]; int FilenameID = FileIDs[Record[Idx++]]; SrcMgr::CharacteristicKind FileKind = (SrcMgr::CharacteristicKind)Record[Idx++]; unsigned IncludeOffset = Record[Idx++]; Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID, FileKind, IncludeOffset)); } LineTable.AddEntry(FileID::get(FID), Entries); } return false; } /// \brief Read a source manager block bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { using namespace SrcMgr; BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor; // Set the source-location entry cursor to the current position in // the stream. This cursor will be used to read the contents of the // source manager block initially, and then lazily read // source-location entries as needed. SLocEntryCursor = F.Stream; // The stream itself is going to skip over the source manager block. if (F.Stream.SkipBlock()) { Error("malformed block record in AST file"); return true; } // Enter the source manager block. if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) { Error("malformed source manager block record in AST file"); return true; } RecordData Record; while (true) { llvm::BitstreamEntry E = SLocEntryCursor.advanceSkippingSubblocks(); switch (E.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return true; case llvm::BitstreamEntry::EndBlock: return false; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); StringRef Blob; switch (SLocEntryCursor.readRecord(E.ID, Record, &Blob)) { default: // Default behavior: ignore. break; case SM_SLOC_FILE_ENTRY: case SM_SLOC_BUFFER_ENTRY: case SM_SLOC_EXPANSION_ENTRY: // Once we hit one of the source location entries, we're done. return false; } } } /// \brief If a header file is not found at the path that we expect it to be /// and the PCH file was moved from its original location, try to resolve the /// file by assuming that header+PCH were moved together and the header is in /// the same place relative to the PCH. static std::string resolveFileRelativeToOriginalDir(const std::string &Filename, const std::string &OriginalDir, const std::string &CurrDir) { assert(OriginalDir != CurrDir && "No point trying to resolve the file if the PCH dir didn't change"); using namespace llvm::sys; SmallString<128> filePath(Filename); fs::make_absolute(filePath); assert(path::is_absolute(OriginalDir)); SmallString<128> currPCHPath(CurrDir); path::const_iterator fileDirI = path::begin(path::parent_path(filePath)), fileDirE = path::end(path::parent_path(filePath)); path::const_iterator origDirI = path::begin(OriginalDir), origDirE = path::end(OriginalDir); // Skip the common path components from filePath and OriginalDir. while (fileDirI != fileDirE && origDirI != origDirE && *fileDirI == *origDirI) { ++fileDirI; ++origDirI; } for (; origDirI != origDirE; ++origDirI) path::append(currPCHPath, ".."); path::append(currPCHPath, fileDirI, fileDirE); path::append(currPCHPath, path::filename(Filename)); return currPCHPath.str(); } bool ASTReader::ReadSLocEntry(int ID) { if (ID == 0) return false; if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { Error("source location entry ID out-of-range for AST file"); return true; } // Local helper to read the (possibly-compressed) buffer data following the // entry record. auto ReadBuffer = [this]( BitstreamCursor &SLocEntryCursor, StringRef Name) -> std::unique_ptr { RecordData Record; StringRef Blob; unsigned Code = SLocEntryCursor.ReadCode(); unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob); if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { if (!llvm::zlib::isAvailable()) { Error("zlib is not available"); return nullptr; } SmallString<0> Uncompressed; if (llvm::Error E = llvm::zlib::uncompress(Blob, Uncompressed, Record[0])) { Error("could not decompress embedded file contents: " + llvm::toString(std::move(E))); return nullptr; } return llvm::MemoryBuffer::getMemBufferCopy(Uncompressed, Name); } else if (RecCode == SM_SLOC_BUFFER_BLOB) { return llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name, true); } else { Error("AST record has invalid code"); return nullptr; } }; ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second; F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]); BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; unsigned BaseOffset = F->SLocEntryBaseOffset; ++NumSLocEntriesRead; llvm::BitstreamEntry Entry = SLocEntryCursor.advance(); if (Entry.Kind != llvm::BitstreamEntry::Record) { Error("incorrectly-formatted source location entry in AST file"); return true; } RecordData Record; StringRef Blob; switch (SLocEntryCursor.readRecord(Entry.ID, Record, &Blob)) { default: Error("incorrectly-formatted source location entry in AST file"); return true; case SM_SLOC_FILE_ENTRY: { // We will detect whether a file changed and return 'Failure' for it, but // we will also try to fail gracefully by setting up the SLocEntry. unsigned InputID = Record[4]; InputFile IF = getInputFile(*F, InputID); const FileEntry *File = IF.getFile(); bool OverriddenBuffer = IF.isOverridden(); // Note that we only check if a File was returned. If it was out-of-date // we have complained but we will continue creating a FileID to recover // gracefully. if (!File) return true; SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) { // This is the module's main file. IncludeLoc = getImportLocation(F); } SrcMgr::CharacteristicKind FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter, ID, BaseOffset + Record[0]); SrcMgr::FileInfo &FileInfo = const_cast(SourceMgr.getSLocEntry(FID).getFile()); FileInfo.NumCreatedFIDs = Record[5]; if (Record[3]) FileInfo.setHasLineDirectives(); const DeclID *FirstDecl = F->FileSortedDecls + Record[6]; unsigned NumFileDecls = Record[7]; if (NumFileDecls) { assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl, NumFileDecls)); } const SrcMgr::ContentCache *ContentCache = SourceMgr.getOrCreateContentCache(File, /*isSystemFile=*/FileCharacter != SrcMgr::C_User); if (OverriddenBuffer && !ContentCache->BufferOverridden && ContentCache->ContentsEntry == ContentCache->OrigEntry && !ContentCache->getRawBuffer()) { auto Buffer = ReadBuffer(SLocEntryCursor, File->getName()); if (!Buffer) return true; SourceMgr.overrideFileContents(File, std::move(Buffer)); } break; } case SM_SLOC_BUFFER_ENTRY: { const char *Name = Blob.data(); unsigned Offset = Record[0]; SrcMgr::CharacteristicKind FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); if (IncludeLoc.isInvalid() && F->isModule()) { IncludeLoc = getImportLocation(F); } auto Buffer = ReadBuffer(SLocEntryCursor, Name); if (!Buffer) return true; SourceMgr.createFileID(std::move(Buffer), FileCharacter, ID, BaseOffset + Offset, IncludeLoc); break; } case SM_SLOC_EXPANSION_ENTRY: { SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]); SourceMgr.createExpansionLoc(SpellingLoc, ReadSourceLocation(*F, Record[2]), ReadSourceLocation(*F, Record[3]), Record[4], ID, BaseOffset + Record[0]); break; } } return false; } std::pair ASTReader::getModuleImportLoc(int ID) { if (ID == 0) return std::make_pair(SourceLocation(), ""); if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { Error("source location entry ID out-of-range for AST file"); return std::make_pair(SourceLocation(), ""); } // Find which module file this entry lands in. ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second; if (!M->isModule()) return std::make_pair(SourceLocation(), ""); // FIXME: Can we map this down to a particular submodule? That would be // ideal. return std::make_pair(M->ImportLoc, StringRef(M->ModuleName)); } /// \brief Find the location where the module F is imported. SourceLocation ASTReader::getImportLocation(ModuleFile *F) { if (F->ImportLoc.isValid()) return F->ImportLoc; // Otherwise we have a PCH. It's considered to be "imported" at the first // location of its includer. if (F->ImportedBy.empty() || !F->ImportedBy[0]) { // Main file is the importer. assert(SourceMgr.getMainFileID().isValid() && "missing main file"); return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); } return F->ImportedBy[0]->FirstLoc; } /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the /// specified cursor. Read the abbreviations that are at the top of the block /// and then leave the cursor pointing into the block. bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) { if (Cursor.EnterSubBlock(BlockID)) return true; while (true) { uint64_t Offset = Cursor.GetCurrentBitNo(); unsigned Code = Cursor.ReadCode(); // We expect all abbrevs to be at the start of the block. if (Code != llvm::bitc::DEFINE_ABBREV) { Cursor.JumpToBit(Offset); return false; } Cursor.ReadAbbrevRecord(); } } Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record, unsigned &Idx) { Token Tok; Tok.startToken(); Tok.setLocation(ReadSourceLocation(F, Record, Idx)); Tok.setLength(Record[Idx++]); if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++])) Tok.setIdentifierInfo(II); Tok.setKind((tok::TokenKind)Record[Idx++]); Tok.setFlag((Token::TokenFlags)Record[Idx++]); return Tok; } MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { BitstreamCursor &Stream = F.MacroCursor; // Keep track of where we are in the stream, then jump back there // after reading this macro. SavedStreamPosition SavedPosition(Stream); Stream.JumpToBit(Offset); RecordData Record; SmallVector MacroArgs; MacroInfo *Macro = nullptr; while (true) { // Advance to the next record, but if we get to the end of the block, don't // pop it (removing all the abbreviations from the cursor) since we want to // be able to reseek within the block and read entries. unsigned Flags = BitstreamCursor::AF_DontPopBlockAtEnd; llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(Flags); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return Macro; case llvm::BitstreamEntry::EndBlock: return Macro; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); PreprocessorRecordTypes RecType = (PreprocessorRecordTypes)Stream.readRecord(Entry.ID, Record); switch (RecType) { case PP_MODULE_MACRO: case PP_MACRO_DIRECTIVE_HISTORY: return Macro; case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: { // If we already have a macro, that means that we've hit the end // of the definition of the macro we were looking for. We're // done. if (Macro) return Macro; unsigned NextIndex = 1; // Skip identifier ID. SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); MacroInfo *MI = PP.AllocateMacroInfo(Loc); MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex)); MI->setIsUsed(Record[NextIndex++]); MI->setUsedForHeaderGuard(Record[NextIndex++]); if (RecType == PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. bool isC99VarArgs = Record[NextIndex++]; bool isGNUVarArgs = Record[NextIndex++]; bool hasCommaPasting = Record[NextIndex++]; MacroArgs.clear(); unsigned NumArgs = Record[NextIndex++]; for (unsigned i = 0; i != NumArgs; ++i) MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++])); // Install function-like macro info. MI->setIsFunctionLike(); if (isC99VarArgs) MI->setIsC99Varargs(); if (isGNUVarArgs) MI->setIsGNUVarargs(); if (hasCommaPasting) MI->setHasCommaPasting(); MI->setArgumentList(MacroArgs, PP.getPreprocessorAllocator()); } // Remember that we saw this macro last so that we add the tokens that // form its body to it. Macro = MI; if (NextIndex + 1 == Record.size() && PP.getPreprocessingRecord() && Record[NextIndex]) { // We have a macro definition. Register the association PreprocessedEntityID GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]); PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); PreprocessingRecord::PPEntityID PPID = PPRec.getPPEntityID(GlobalID - 1, /*isLoaded=*/true); MacroDefinitionRecord *PPDef = cast_or_null( PPRec.getPreprocessedEntity(PPID)); if (PPDef) PPRec.RegisterMacroDefinition(Macro, PPDef); } ++NumMacrosRead; break; } case PP_TOKEN: { // If we see a TOKEN before a PP_MACRO_*, then the file is // erroneous, just pretend we didn't see this. if (!Macro) break; unsigned Idx = 0; Token Tok = ReadToken(F, Record, Idx); Macro->AddTokenToBody(Tok); break; } } } } PreprocessedEntityID ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const { if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::const_iterator I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS); assert(I != M.PreprocessedEntityRemap.end() && "Invalid index into preprocessed entity index remap"); return LocalID + I->second; } unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) { return llvm::hash_combine(ikey.Size, ikey.ModTime); } HeaderFileInfoTrait::internal_key_type HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) { internal_key_type ikey = {FE->getSize(), M.HasTimestamps ? FE->getModificationTime() : 0, FE->getName(), /*Imported*/ false}; return ikey; } bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) { if (a.Size != b.Size || (a.ModTime && b.ModTime && a.ModTime != b.ModTime)) return false; if (llvm::sys::path::is_absolute(a.Filename) && a.Filename == b.Filename) return true; // Determine whether the actual files are equivalent. FileManager &FileMgr = Reader.getFileManager(); auto GetFile = [&](const internal_key_type &Key) -> const FileEntry* { if (!Key.Imported) return FileMgr.getFile(Key.Filename); std::string Resolved = Key.Filename; Reader.ResolveImportedPath(M, Resolved); return FileMgr.getFile(Resolved); }; const FileEntry *FEA = GetFile(a); const FileEntry *FEB = GetFile(b); return FEA && FEA == FEB; } std::pair HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { using namespace llvm::support; unsigned KeyLen = (unsigned) endian::readNext(d); unsigned DataLen = (unsigned) *d++; return std::make_pair(KeyLen, DataLen); } HeaderFileInfoTrait::internal_key_type HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) { using namespace llvm::support; internal_key_type ikey; ikey.Size = off_t(endian::readNext(d)); ikey.ModTime = time_t(endian::readNext(d)); ikey.Filename = (const char *)d; ikey.Imported = true; return ikey; } HeaderFileInfoTrait::data_type HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, unsigned DataLen) { const unsigned char *End = d + DataLen; using namespace llvm::support; HeaderFileInfo HFI; unsigned Flags = *d++; // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp. HFI.isImport |= (Flags >> 4) & 0x01; HFI.isPragmaOnce |= (Flags >> 3) & 0x01; HFI.DirInfo = (Flags >> 1) & 0x03; HFI.IndexHeaderMapHeader = Flags & 0x01; // FIXME: Find a better way to handle this. Maybe just store a // "has been included" flag? HFI.NumIncludes = std::max(endian::readNext(d), HFI.NumIncludes); HFI.ControllingMacroID = Reader.getGlobalIdentifierID( M, endian::readNext(d)); if (unsigned FrameworkOffset = endian::readNext(d)) { // The framework offset is 1 greater than the actual offset, // since 0 is used as an indicator for "no framework name". StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1); HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); } assert((End - d) % 4 == 0 && "Wrong data length in HeaderFileInfo deserialization"); while (d != End) { uint32_t LocalSMID = endian::readNext(d); auto HeaderRole = static_cast(LocalSMID & 3); LocalSMID >>= 2; // This header is part of a module. Associate it with the module to enable // implicit module import. SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID); Module *Mod = Reader.getSubmodule(GlobalSMID); FileManager &FileMgr = Reader.getFileManager(); ModuleMap &ModMap = Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); std::string Filename = key.Filename; if (key.Imported) Reader.ResolveImportedPath(M, Filename); // FIXME: This is not always the right filename-as-written, but we're not // going to use this information to rebuild the module, so it doesn't make // a lot of difference. Module::Header H = { key.Filename, FileMgr.getFile(Filename) }; ModMap.addHeader(Mod, H, HeaderRole, /*Imported*/true); HFI.isModuleHeader |= !(HeaderRole & ModuleMap::TextualHeader); } // This HeaderFileInfo was externally loaded. HFI.External = true; HFI.IsValid = true; return HFI; } void ASTReader::addPendingMacro(IdentifierInfo *II, ModuleFile *M, uint64_t MacroDirectivesOffset) { assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset)); } void ASTReader::ReadDefinedMacros() { // Note that we are loading defined macros. Deserializing Macros(this); for (ModuleFile &I : llvm::reverse(ModuleMgr)) { BitstreamCursor &MacroCursor = I.MacroCursor; // If there was no preprocessor block, skip this file. if (MacroCursor.getBitcodeBytes().empty()) continue; BitstreamCursor Cursor = MacroCursor; Cursor.JumpToBit(I.MacroStartOffset); RecordData Record; while (true) { llvm::BitstreamEntry E = Cursor.advanceSkippingSubblocks(); switch (E.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return; case llvm::BitstreamEntry::EndBlock: goto NextCursor; case llvm::BitstreamEntry::Record: Record.clear(); switch (Cursor.readRecord(E.ID, Record)) { default: // Default behavior: ignore. break; case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: { IdentifierInfo *II = getLocalIdentifier(I, Record[0]); if (II->isOutOfDate()) updateOutOfDateIdentifier(*II); break; } case PP_TOKEN: // Ignore tokens. break; } break; } } NextCursor: ; } } namespace { /// \brief Visitor class used to look up identifirs in an AST file. class IdentifierLookupVisitor { StringRef Name; unsigned NameHash; unsigned PriorGeneration; unsigned &NumIdentifierLookups; unsigned &NumIdentifierLookupHits; IdentifierInfo *Found; public: IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration, unsigned &NumIdentifierLookups, unsigned &NumIdentifierLookupHits) : Name(Name), NameHash(ASTIdentifierLookupTrait::ComputeHash(Name)), PriorGeneration(PriorGeneration), NumIdentifierLookups(NumIdentifierLookups), NumIdentifierLookupHits(NumIdentifierLookupHits), Found() { } bool operator()(ModuleFile &M) { // If we've already searched this module file, skip it now. if (M.Generation <= PriorGeneration) return true; ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; if (!IdTable) return false; ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M, Found); ++NumIdentifierLookups; ASTIdentifierLookupTable::iterator Pos = IdTable->find_hashed(Name, NameHash, &Trait); if (Pos == IdTable->end()) return false; // Dereferencing the iterator has the effect of building the // IdentifierInfo node and populating it with the various // declarations it needs. ++NumIdentifierLookupHits; Found = *Pos; return true; } // \brief Retrieve the identifier info found within the module // files. IdentifierInfo *getIdentifierInfo() const { return Found; } }; } // end anonymous namespace void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { // Note that we are loading an identifier. Deserializing AnIdentifier(this); unsigned PriorGeneration = 0; if (getContext().getLangOpts().Modules) PriorGeneration = IdentifierGeneration[&II]; // If there is a global index, look there first to determine which modules // provably do not have any results for this identifier. GlobalModuleIndex::HitSet Hits; GlobalModuleIndex::HitSet *HitsPtr = nullptr; if (!loadGlobalIndex()) { if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) { HitsPtr = &Hits; } } IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration, NumIdentifierLookups, NumIdentifierLookupHits); ModuleMgr.visit(Visitor, HitsPtr); markIdentifierUpToDate(&II); } void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) { if (!II) return; II->setOutOfDate(false); // Update the generation for this identifier. if (getContext().getLangOpts().Modules) IdentifierGeneration[II] = getGeneration(); } void ASTReader::resolvePendingMacro(IdentifierInfo *II, const PendingMacroInfo &PMInfo) { ModuleFile &M = *PMInfo.M; BitstreamCursor &Cursor = M.MacroCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(PMInfo.MacroDirectivesOffset); struct ModuleMacroRecord { SubmoduleID SubModID; MacroInfo *MI; SmallVector Overrides; }; llvm::SmallVector ModuleMacros; // We expect to see a sequence of PP_MODULE_MACRO records listing exported // macros, followed by a PP_MACRO_DIRECTIVE_HISTORY record with the complete // macro histroy. RecordData Record; while (true) { llvm::BitstreamEntry Entry = Cursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd); if (Entry.Kind != llvm::BitstreamEntry::Record) { Error("malformed block record in AST file"); return; } Record.clear(); switch ((PreprocessorRecordTypes)Cursor.readRecord(Entry.ID, Record)) { case PP_MACRO_DIRECTIVE_HISTORY: break; case PP_MODULE_MACRO: { ModuleMacros.push_back(ModuleMacroRecord()); auto &Info = ModuleMacros.back(); Info.SubModID = getGlobalSubmoduleID(M, Record[0]); Info.MI = getMacro(getGlobalMacroID(M, Record[1])); for (int I = 2, N = Record.size(); I != N; ++I) Info.Overrides.push_back(getGlobalSubmoduleID(M, Record[I])); continue; } default: Error("malformed block record in AST file"); return; } // We found the macro directive history; that's the last record // for this macro. break; } // Module macros are listed in reverse dependency order. { std::reverse(ModuleMacros.begin(), ModuleMacros.end()); llvm::SmallVector Overrides; for (auto &MMR : ModuleMacros) { Overrides.clear(); for (unsigned ModID : MMR.Overrides) { Module *Mod = getSubmodule(ModID); auto *Macro = PP.getModuleMacro(Mod, II); assert(Macro && "missing definition for overridden macro"); Overrides.push_back(Macro); } bool Inserted = false; Module *Owner = getSubmodule(MMR.SubModID); PP.addModuleMacro(Owner, II, MMR.MI, Overrides, Inserted); } } // Don't read the directive history for a module; we don't have anywhere // to put it. if (M.isModule()) return; // Deserialize the macro directives history in reverse source-order. MacroDirective *Latest = nullptr, *Earliest = nullptr; unsigned Idx = 0, N = Record.size(); while (Idx < N) { MacroDirective *MD = nullptr; SourceLocation Loc = ReadSourceLocation(M, Record, Idx); MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++]; switch (K) { case MacroDirective::MD_Define: { MacroInfo *MI = getMacro(getGlobalMacroID(M, Record[Idx++])); MD = PP.AllocateDefMacroDirective(MI, Loc); break; } case MacroDirective::MD_Undefine: { MD = PP.AllocateUndefMacroDirective(Loc); break; } case MacroDirective::MD_Visibility: bool isPublic = Record[Idx++]; MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic); break; } if (!Latest) Latest = MD; if (Earliest) Earliest->setPrevious(MD); Earliest = MD; } if (Latest) PP.setLoadedMacroDirective(II, Earliest, Latest); } ASTReader::InputFileInfo ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) { // Go find this input file. BitstreamCursor &Cursor = F.InputFilesCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(F.InputFileOffsets[ID-1]); unsigned Code = Cursor.ReadCode(); RecordData Record; StringRef Blob; unsigned Result = Cursor.readRecord(Code, Record, &Blob); assert(static_cast(Result) == INPUT_FILE && "invalid record type for input file"); (void)Result; assert(Record[0] == ID && "Bogus stored ID or offset"); InputFileInfo R; R.StoredSize = static_cast(Record[1]); R.StoredTime = static_cast(Record[2]); R.Overridden = static_cast(Record[3]); R.Transient = static_cast(Record[4]); R.Filename = Blob; ResolveImportedPath(F, R.Filename); return R; } static unsigned moduleKindForDiagnostic(ModuleKind Kind); InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // If this ID is bogus, just return an empty input file. if (ID == 0 || ID > F.InputFilesLoaded.size()) return InputFile(); // If we've already loaded this input file, return it. if (F.InputFilesLoaded[ID-1].getFile()) return F.InputFilesLoaded[ID-1]; if (F.InputFilesLoaded[ID-1].isNotFound()) return InputFile(); // Go find this input file. BitstreamCursor &Cursor = F.InputFilesCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(F.InputFileOffsets[ID-1]); InputFileInfo FI = readInputFileInfo(F, ID); off_t StoredSize = FI.StoredSize; time_t StoredTime = FI.StoredTime; bool Overridden = FI.Overridden; bool Transient = FI.Transient; StringRef Filename = FI.Filename; const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false); // If we didn't find the file, resolve it relative to the // original directory from which this AST file was created. if (File == nullptr && !F.OriginalDir.empty() && !CurrentDir.empty() && F.OriginalDir != CurrentDir) { std::string Resolved = resolveFileRelativeToOriginalDir(Filename, F.OriginalDir, CurrentDir); if (!Resolved.empty()) File = FileMgr.getFile(Resolved); } // For an overridden file, create a virtual file with the stored // size/timestamp. if ((Overridden || Transient) && File == nullptr) File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime); if (File == nullptr) { if (Complain) { std::string ErrorStr = "could not find file '"; ErrorStr += Filename; ErrorStr += "' referenced by AST file '"; ErrorStr += F.FileName; ErrorStr += "'"; Error(ErrorStr); } // Record that we didn't find the file. F.InputFilesLoaded[ID-1] = InputFile::getNotFound(); return InputFile(); } // Check if there was a request to override the contents of the file // that was part of the precompiled header. Overridding such a file // can lead to problems when lexing using the source locations from the // PCH. SourceManager &SM = getSourceManager(); // FIXME: Reject if the overrides are different. if ((!Overridden && !Transient) && SM.isFileOverridden(File)) { if (Complain) Error(diag::err_fe_pch_file_overridden, Filename); // After emitting the diagnostic, recover by disabling the override so // that the original file will be used. // // FIXME: This recovery is just as broken as the original state; there may // be another precompiled module that's using the overridden contents, or // we might be half way through parsing it. Instead, we should treat the // overridden contents as belonging to a separate FileEntry. SM.disableFileContentsOverride(File); // The FileEntry is a virtual file entry with the size of the contents // that would override the original contents. Set it to the original's // size/time. FileMgr.modifyFileEntry(const_cast(File), StoredSize, StoredTime); } bool IsOutOfDate = false; // For an overridden file, there is nothing to validate. if (!Overridden && // (StoredSize != File->getSize() || (StoredTime && StoredTime != File->getModificationTime() && !DisableValidation) )) { if (Complain) { // Build a list of the PCH imports that got us here (in reverse). SmallVector ImportStack(1, &F); while (ImportStack.back()->ImportedBy.size() > 0) ImportStack.push_back(ImportStack.back()->ImportedBy[0]); // The top-level PCH is stale. StringRef TopLevelPCHName(ImportStack.back()->FileName); unsigned DiagnosticKind = moduleKindForDiagnostic(ImportStack.back()->Kind); if (DiagnosticKind == 0) Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName); else if (DiagnosticKind == 1) Error(diag::err_fe_module_file_modified, Filename, TopLevelPCHName); else Error(diag::err_fe_ast_file_modified, Filename, TopLevelPCHName); // Print the import stack. if (ImportStack.size() > 1 && !Diags.isDiagnosticInFlight()) { Diag(diag::note_pch_required_by) << Filename << ImportStack[0]->FileName; for (unsigned I = 1; I < ImportStack.size(); ++I) Diag(diag::note_pch_required_by) << ImportStack[I-1]->FileName << ImportStack[I]->FileName; } if (!Diags.isDiagnosticInFlight()) Diag(diag::note_pch_rebuild_required) << TopLevelPCHName; } IsOutOfDate = true; } // FIXME: If the file is overridden and we've already opened it, // issue an error (or split it into a separate FileEntry). InputFile IF = InputFile(File, Overridden || Transient, IsOutOfDate); // Note that we've loaded this input file. F.InputFilesLoaded[ID-1] = IF; return IF; } /// \brief If we are loading a relocatable PCH or module file, and the filename /// is not an absolute path, add the system or module root to the beginning of /// the file name. void ASTReader::ResolveImportedPath(ModuleFile &M, std::string &Filename) { // Resolve relative to the base directory, if we have one. if (!M.BaseDirectory.empty()) return ResolveImportedPath(Filename, M.BaseDirectory); } void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) { if (Filename.empty() || llvm::sys::path::is_absolute(Filename)) return; SmallString<128> Buffer; llvm::sys::path::append(Buffer, Prefix, Filename); Filename.assign(Buffer.begin(), Buffer.end()); } static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) { switch (ARR) { case ASTReader::Failure: return true; case ASTReader::Missing: return !(Caps & ASTReader::ARR_Missing); case ASTReader::OutOfDate: return !(Caps & ASTReader::ARR_OutOfDate); case ASTReader::VersionMismatch: return !(Caps & ASTReader::ARR_VersionMismatch); case ASTReader::ConfigurationMismatch: return !(Caps & ASTReader::ARR_ConfigurationMismatch); case ASTReader::HadErrors: return true; case ASTReader::Success: return false; } llvm_unreachable("unknown ASTReadResult"); } ASTReader::ASTReadResult ASTReader::ReadOptionsBlock( BitstreamCursor &Stream, unsigned ClientLoadCapabilities, bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener, std::string &SuggestedPredefines) { if (Stream.EnterSubBlock(OPTIONS_BLOCK_ID)) return Failure; // Read all of the records in the options block. RecordData Record; ASTReadResult Result = Success; while (true) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: case llvm::BitstreamEntry::SubBlock: return Failure; case llvm::BitstreamEntry::EndBlock: return Result; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read and process a record. Record.clear(); switch ((OptionsRecordTypes)Stream.readRecord(Entry.ID, Record)) { case LANGUAGE_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (ParseLanguageOptions(Record, Complain, Listener, AllowCompatibleConfigurationMismatch)) Result = ConfigurationMismatch; break; } case TARGET_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (ParseTargetOptions(Record, Complain, Listener, AllowCompatibleConfigurationMismatch)) Result = ConfigurationMismatch; break; } case FILE_SYSTEM_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (!AllowCompatibleConfigurationMismatch && ParseFileSystemOptions(Record, Complain, Listener)) Result = ConfigurationMismatch; break; } case HEADER_SEARCH_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (!AllowCompatibleConfigurationMismatch && ParseHeaderSearchOptions(Record, Complain, Listener)) Result = ConfigurationMismatch; break; } case PREPROCESSOR_OPTIONS: bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (!AllowCompatibleConfigurationMismatch && ParsePreprocessorOptions(Record, Complain, Listener, SuggestedPredefines)) Result = ConfigurationMismatch; break; } } } ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F, SmallVectorImpl &Loaded, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; ASTReadResult Result = Success; if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { Error("malformed block record in AST file"); return Failure; } // Lambda to read the unhashed control block the first time it's called. // // For PCM files, the unhashed control block cannot be read until after the // MODULE_NAME record. However, PCH files have no MODULE_NAME, and yet still // need to look ahead before reading the IMPORTS record. For consistency, // this block is always read somehow (see BitstreamEntry::EndBlock). bool HasReadUnhashedControlBlock = false; auto readUnhashedControlBlockOnce = [&]() { if (!HasReadUnhashedControlBlock) { HasReadUnhashedControlBlock = true; if (ASTReadResult Result = readUnhashedControlBlock(F, ImportedBy, ClientLoadCapabilities)) return Result; } return Success; }; // Read all of the records and blocks in the control block. RecordData Record; unsigned NumInputs = 0; unsigned NumUserInputs = 0; while (true) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return Failure; case llvm::BitstreamEntry::EndBlock: { // Validate the module before returning. This call catches an AST with // no module name and no imports. if (ASTReadResult Result = readUnhashedControlBlockOnce()) return Result; // Validate input files. const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); // All user input files reside at the index range [0, NumUserInputs), and // system input files reside at [NumUserInputs, NumInputs). For explicitly // loaded module files, ignore missing inputs. if (!DisableValidation && F.Kind != MK_ExplicitModule && F.Kind != MK_PrebuiltModule) { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; // If we are reading a module, we will create a verification timestamp, // so we verify all input files. Otherwise, verify only user input // files. unsigned N = NumUserInputs; if (ValidateSystemInputs || (HSOpts.ModulesValidateOncePerBuildSession && F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp && F.Kind == MK_ImplicitModule)) N = NumInputs; for (unsigned I = 0; I < N; ++I) { InputFile IF = getInputFile(F, I+1, Complain); if (!IF.getFile() || IF.isOutOfDate()) return OutOfDate; } } if (Listener) Listener->visitModuleFile(F.FileName, F.Kind); if (Listener && Listener->needsInputFileVisitation()) { unsigned N = Listener->needsSystemInputFileVisitation() ? NumInputs : NumUserInputs; for (unsigned I = 0; I < N; ++I) { bool IsSystem = I >= NumUserInputs; InputFileInfo FI = readInputFileInfo(F, I+1); Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden, F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule); } } return Result; } case llvm::BitstreamEntry::SubBlock: switch (Entry.ID) { case INPUT_FILES_BLOCK_ID: F.InputFilesCursor = Stream; if (Stream.SkipBlock() || // Skip with the main cursor // Read the abbreviations ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) { Error("malformed block record in AST file"); return Failure; } continue; case OPTIONS_BLOCK_ID: // If we're reading the first module for this group, check its options // are compatible with ours. For modules it imports, no further checking // is required, because we checked them when we built it. if (Listener && !ImportedBy) { // Should we allow the configuration of the module file to differ from // the configuration of the current translation unit in a compatible // way? // // FIXME: Allow this for files explicitly specified with -include-pch. bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule; Result = ReadOptionsBlock(Stream, ClientLoadCapabilities, AllowCompatibleConfigurationMismatch, *Listener, SuggestedPredefines); if (Result == Failure) { Error("malformed block record in AST file"); return Result; } if (DisableValidation || (AllowConfigurationMismatch && Result == ConfigurationMismatch)) Result = Success; // If we can't load the module, exit early since we likely // will rebuild the module anyway. The stream may be in the // middle of a block. if (Result != Success) return Result; } else if (Stream.SkipBlock()) { Error("malformed block record in AST file"); return Failure; } continue; default: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); return Failure; } continue; } case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read and process a record. Record.clear(); StringRef Blob; switch ((ControlRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) { case METADATA: { if (Record[0] != VERSION_MAJOR && !DisableValidation) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) Diag(Record[0] < VERSION_MAJOR? diag::err_pch_version_too_old : diag::err_pch_version_too_new); return VersionMismatch; } bool hasErrors = Record[6]; if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { Diag(diag::err_pch_with_compiler_errors); return HadErrors; } if (hasErrors) { Diags.ErrorOccurred = true; Diags.UncompilableErrorOccurred = true; Diags.UnrecoverableErrorOccurred = true; } F.RelocatablePCH = Record[4]; // Relative paths in a relocatable PCH are relative to our sysroot. if (F.RelocatablePCH) F.BaseDirectory = isysroot.empty() ? "/" : isysroot; F.HasTimestamps = Record[5]; const std::string &CurBranch = getClangFullRepositoryVersion(); StringRef ASTBranch = Blob; if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) Diag(diag::err_pch_different_branch) << ASTBranch << CurBranch; return VersionMismatch; } break; } case IMPORTS: { // Validate the AST before processing any imports (otherwise, untangling // them can be error-prone and expensive). A module will have a name and // will already have been validated, but this catches the PCH case. if (ASTReadResult Result = readUnhashedControlBlockOnce()) return Result; // Load each of the imported PCH files. unsigned Idx = 0, N = Record.size(); while (Idx < N) { // Read information about the AST file. ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; // The import location will be the local one for now; we will adjust // all import locations of module imports after the global source // location info are setup, in ReadAST. SourceLocation ImportLoc = ReadUntranslatedSourceLocation(Record[Idx++]); off_t StoredSize = (off_t)Record[Idx++]; time_t StoredModTime = (time_t)Record[Idx++]; ASTFileSignature StoredSignature = { {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], (uint32_t)Record[Idx++]}}}; auto ImportedFile = ReadPath(F, Record, Idx); // If our client can't cope with us being out of date, we can't cope with // our dependency being missing. unsigned Capabilities = ClientLoadCapabilities; if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Capabilities &= ~ARR_Missing; // Load the AST file. auto Result = ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded, StoredSize, StoredModTime, StoredSignature, Capabilities); // If we diagnosed a problem, produce a backtrace. if (isDiagnosedResult(Result, Capabilities)) Diag(diag::note_module_file_imported_by) << F.FileName << !F.ModuleName.empty() << F.ModuleName; switch (Result) { case Failure: return Failure; // If we have to ignore the dependency, we'll have to ignore this too. case Missing: case OutOfDate: return OutOfDate; case VersionMismatch: return VersionMismatch; case ConfigurationMismatch: return ConfigurationMismatch; case HadErrors: return HadErrors; case Success: break; } } break; } case ORIGINAL_FILE: F.OriginalSourceFileID = FileID::get(Record[0]); F.ActualOriginalSourceFileName = Blob; F.OriginalSourceFileName = F.ActualOriginalSourceFileName; ResolveImportedPath(F, F.OriginalSourceFileName); break; case ORIGINAL_FILE_ID: F.OriginalSourceFileID = FileID::get(Record[0]); break; case ORIGINAL_PCH_DIR: F.OriginalDir = Blob; break; case MODULE_NAME: F.ModuleName = Blob; if (Listener) Listener->ReadModuleName(F.ModuleName); // Validate the AST as soon as we have a name so we can exit early on // failure. if (ASTReadResult Result = readUnhashedControlBlockOnce()) return Result; break; case MODULE_DIRECTORY: { assert(!F.ModuleName.empty() && "MODULE_DIRECTORY found before MODULE_NAME"); // If we've already loaded a module map file covering this module, we may // have a better path for it (relative to the current build). Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName); if (M && M->Directory) { // If we're implicitly loading a module, the base directory can't // change between the build and use. if (F.Kind != MK_ExplicitModule && F.Kind != MK_PrebuiltModule) { const DirectoryEntry *BuildDir = PP.getFileManager().getDirectory(Blob); if (!BuildDir || BuildDir != M->Directory) { if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Diag(diag::err_imported_module_relocated) << F.ModuleName << Blob << M->Directory->getName(); return OutOfDate; } } F.BaseDirectory = M->Directory->getName(); } else { F.BaseDirectory = Blob; } break; } case MODULE_MAP_FILE: if (ASTReadResult Result = ReadModuleMapFileBlock(Record, F, ImportedBy, ClientLoadCapabilities)) return Result; break; case INPUT_FILE_OFFSETS: NumInputs = Record[0]; NumUserInputs = Record[1]; F.InputFileOffsets = (const llvm::support::unaligned_uint64_t *)Blob.data(); F.InputFilesLoaded.resize(NumInputs); F.NumUserInputFiles = NumUserInputs; break; } } } ASTReader::ASTReadResult ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; if (Stream.EnterSubBlock(AST_BLOCK_ID)) { Error("malformed block record in AST file"); return Failure; } // Read all of the records and blocks for the AST file. RecordData Record; while (true) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: Error("error at end of module block in AST file"); return Failure; case llvm::BitstreamEntry::EndBlock: { // Outside of C++, we do not store a lookup map for the translation unit. // Instead, mark it as needing a lookup map to be built if this module // contains any declarations lexically within it (which it always does!). // This usually has no cost, since we very rarely need the lookup map for // the translation unit outside C++. DeclContext *DC = Context.getTranslationUnitDecl(); if (DC->hasExternalLexicalStorage() && !getContext().getLangOpts().CPlusPlus) DC->setMustBuildLookupTable(); return Success; } case llvm::BitstreamEntry::SubBlock: switch (Entry.ID) { case DECLTYPES_BLOCK_ID: // We lazily load the decls block, but we want to set up the // DeclsCursor cursor to point into it. Clone our current bitcode // cursor to it, enter the block and read the abbrevs in that block. // With the main cursor, we just skip over it. F.DeclsCursor = Stream; if (Stream.SkipBlock() || // Skip with the main cursor. // Read the abbrevs. ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) { Error("malformed block record in AST file"); return Failure; } break; case PREPROCESSOR_BLOCK_ID: F.MacroCursor = Stream; if (!PP.getExternalSource()) PP.setExternalSource(this); if (Stream.SkipBlock() || ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) { Error("malformed block record in AST file"); return Failure; } F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo(); break; case PREPROCESSOR_DETAIL_BLOCK_ID: F.PreprocessorDetailCursor = Stream; if (Stream.SkipBlock() || ReadBlockAbbrevs(F.PreprocessorDetailCursor, PREPROCESSOR_DETAIL_BLOCK_ID)) { Error("malformed preprocessor detail record in AST file"); return Failure; } F.PreprocessorDetailStartOffset = F.PreprocessorDetailCursor.GetCurrentBitNo(); if (!PP.getPreprocessingRecord()) PP.createPreprocessingRecord(); if (!PP.getPreprocessingRecord()->getExternalSource()) PP.getPreprocessingRecord()->SetExternalSource(*this); break; case SOURCE_MANAGER_BLOCK_ID: if (ReadSourceManagerBlock(F)) return Failure; break; case SUBMODULE_BLOCK_ID: if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities)) return Result; break; case COMMENTS_BLOCK_ID: { BitstreamCursor C = Stream; if (Stream.SkipBlock() || ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) { Error("malformed comments block in AST file"); return Failure; } CommentsCursors.push_back(std::make_pair(C, &F)); break; } default: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); return Failure; } break; } continue; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read and process a record. Record.clear(); StringRef Blob; switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) { default: // Default behavior: ignore. break; case TYPE_OFFSET: { if (F.LocalNumTypes != 0) { Error("duplicate TYPE_OFFSET record in AST file"); return Failure; } F.TypeOffsets = (const uint32_t *)Blob.data(); F.LocalNumTypes = Record[0]; unsigned LocalBaseTypeIndex = Record[1]; F.BaseTypeIndex = getTotalNumTypes(); if (F.LocalNumTypes > 0) { // Introduce the global -> local mapping for types within this module. GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F)); // Introduce the local -> global mapping for types within this module. F.TypeRemap.insertOrReplace( std::make_pair(LocalBaseTypeIndex, F.BaseTypeIndex - LocalBaseTypeIndex)); TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes); } break; } case DECL_OFFSET: { if (F.LocalNumDecls != 0) { Error("duplicate DECL_OFFSET record in AST file"); return Failure; } F.DeclOffsets = (const DeclOffset *)Blob.data(); F.LocalNumDecls = Record[0]; unsigned LocalBaseDeclID = Record[1]; F.BaseDeclID = getTotalNumDecls(); if (F.LocalNumDecls > 0) { // Introduce the global -> local mapping for declarations within this // module. GlobalDeclMap.insert( std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F)); // Introduce the local -> global mapping for declarations within this // module. F.DeclRemap.insertOrReplace( std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID)); // Introduce the global -> local mapping for declarations within this // module. F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID; DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls); } break; } case TU_UPDATE_LEXICAL: { DeclContext *TU = Context.getTranslationUnitDecl(); LexicalContents Contents( reinterpret_cast( Blob.data()), static_cast(Blob.size() / 4)); TULexicalDecls.push_back(std::make_pair(&F, Contents)); TU->setHasExternalLexicalStorage(true); break; } case UPDATE_VISIBLE: { unsigned Idx = 0; serialization::DeclID ID = ReadDeclID(F, Record, Idx); auto *Data = (const unsigned char*)Blob.data(); PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data}); // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) PendingUpdateRecords.push_back(std::make_pair(ID, D)); break; } case IDENTIFIER_TABLE: F.IdentifierTableData = Blob.data(); if (Record[0]) { F.IdentifierLookupTable = ASTIdentifierLookupTable::Create( (const unsigned char *)F.IdentifierTableData + Record[0], (const unsigned char *)F.IdentifierTableData + sizeof(uint32_t), (const unsigned char *)F.IdentifierTableData, ASTIdentifierLookupTrait(*this, F)); PP.getIdentifierTable().setExternalIdentifierLookup(this); } break; case IDENTIFIER_OFFSET: { if (F.LocalNumIdentifiers != 0) { Error("duplicate IDENTIFIER_OFFSET record in AST file"); return Failure; } F.IdentifierOffsets = (const uint32_t *)Blob.data(); F.LocalNumIdentifiers = Record[0]; unsigned LocalBaseIdentifierID = Record[1]; F.BaseIdentifierID = getTotalNumIdentifiers(); if (F.LocalNumIdentifiers > 0) { // Introduce the global -> local mapping for identifiers within this // module. GlobalIdentifierMap.insert(std::make_pair(getTotalNumIdentifiers() + 1, &F)); // Introduce the local -> global mapping for identifiers within this // module. F.IdentifierRemap.insertOrReplace( std::make_pair(LocalBaseIdentifierID, F.BaseIdentifierID - LocalBaseIdentifierID)); IdentifiersLoaded.resize(IdentifiersLoaded.size() + F.LocalNumIdentifiers); } break; } case INTERESTING_IDENTIFIERS: F.PreloadIdentifierOffsets.assign(Record.begin(), Record.end()); break; case EAGERLY_DESERIALIZED_DECLS: // FIXME: Skip reading this record if our ASTConsumer doesn't care // about "interesting" decls (for instance, if we're building a module). for (unsigned I = 0, N = Record.size(); I != N; ++I) EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); break; case MODULAR_CODEGEN_DECLS: // FIXME: Skip reading this record if our ASTConsumer doesn't care about // them (ie: if we're not codegenerating this module). if (F.Kind == MK_MainFile) for (unsigned I = 0, N = Record.size(); I != N; ++I) EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); break; case SPECIAL_TYPES: if (SpecialTypes.empty()) { for (unsigned I = 0, N = Record.size(); I != N; ++I) SpecialTypes.push_back(getGlobalTypeID(F, Record[I])); break; } if (SpecialTypes.size() != Record.size()) { Error("invalid special-types record"); return Failure; } for (unsigned I = 0, N = Record.size(); I != N; ++I) { serialization::TypeID ID = getGlobalTypeID(F, Record[I]); if (!SpecialTypes[I]) SpecialTypes[I] = ID; // FIXME: If ID && SpecialTypes[I] != ID, do we need a separate // merge step? } break; case STATISTICS: TotalNumStatements += Record[0]; TotalNumMacros += Record[1]; TotalLexicalDeclContexts += Record[2]; TotalVisibleDeclContexts += Record[3]; break; case UNUSED_FILESCOPED_DECLS: for (unsigned I = 0, N = Record.size(); I != N; ++I) UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I])); break; case DELEGATING_CTORS: for (unsigned I = 0, N = Record.size(); I != N; ++I) DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I])); break; case WEAK_UNDECLARED_IDENTIFIERS: if (Record.size() % 4 != 0) { Error("invalid weak identifiers record"); return Failure; } // FIXME: Ignore weak undeclared identifiers from non-original PCH // files. This isn't the way to do it :) WeakUndeclaredIdentifiers.clear(); // Translate the weak, undeclared identifiers into global IDs. for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) { WeakUndeclaredIdentifiers.push_back( getGlobalIdentifierID(F, Record[I++])); WeakUndeclaredIdentifiers.push_back( getGlobalIdentifierID(F, Record[I++])); WeakUndeclaredIdentifiers.push_back( ReadSourceLocation(F, Record, I).getRawEncoding()); WeakUndeclaredIdentifiers.push_back(Record[I++]); } break; case SELECTOR_OFFSETS: { F.SelectorOffsets = (const uint32_t *)Blob.data(); F.LocalNumSelectors = Record[0]; unsigned LocalBaseSelectorID = Record[1]; F.BaseSelectorID = getTotalNumSelectors(); if (F.LocalNumSelectors > 0) { // Introduce the global -> local mapping for selectors within this // module. GlobalSelectorMap.insert(std::make_pair(getTotalNumSelectors()+1, &F)); // Introduce the local -> global mapping for selectors within this // module. F.SelectorRemap.insertOrReplace( std::make_pair(LocalBaseSelectorID, F.BaseSelectorID - LocalBaseSelectorID)); SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors); } break; } case METHOD_POOL: F.SelectorLookupTableData = (const unsigned char *)Blob.data(); if (Record[0]) F.SelectorLookupTable = ASTSelectorLookupTable::Create( F.SelectorLookupTableData + Record[0], F.SelectorLookupTableData, ASTSelectorLookupTrait(*this, F)); TotalNumMethodPoolEntries += Record[1]; break; case REFERENCED_SELECTOR_POOL: if (!Record.empty()) { for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) { ReferencedSelectorsData.push_back(getGlobalSelectorID(F, Record[Idx++])); ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx). getRawEncoding()); } } break; case PP_COUNTER_VALUE: if (!Record.empty() && Listener) Listener->ReadCounter(F, Record[0]); break; case FILE_SORTED_DECLS: F.FileSortedDecls = (const DeclID *)Blob.data(); F.NumFileSortedDecls = Record[0]; break; case SOURCE_LOCATION_OFFSETS: { F.SLocEntryOffsets = (const uint32_t *)Blob.data(); F.LocalNumSLocEntries = Record[0]; unsigned SLocSpaceSize = Record[1]; std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, SLocSpaceSize); if (!F.SLocEntryBaseID) { Error("ran out of source locations"); break; } // Make our entry in the range map. BaseID is negative and growing, so // we invert it. Because we invert it, though, we need the other end of // the range. unsigned RangeStart = unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1; GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F)); F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset); // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing. assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0); GlobalSLocOffsetMap.insert( std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset - SLocSpaceSize,&F)); // Initialize the remapping table. // Invalid stays invalid. F.SLocRemap.insertOrReplace(std::make_pair(0U, 0)); // This module. Base was 2 when being compiled. F.SLocRemap.insertOrReplace(std::make_pair(2U, static_cast(F.SLocEntryBaseOffset - 2))); TotalNumSLocEntries += F.LocalNumSLocEntries; break; } case MODULE_OFFSET_MAP: F.ModuleOffsetMap = Blob; break; case SOURCE_MANAGER_LINE_TABLE: if (ParseLineTable(F, Record)) return Failure; break; case SOURCE_LOCATION_PRELOADS: { // Need to transform from the local view (1-based IDs) to the global view, // which is based off F.SLocEntryBaseID. if (!F.PreloadSLocEntries.empty()) { Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file"); return Failure; } F.PreloadSLocEntries.swap(Record); break; } case EXT_VECTOR_DECLS: for (unsigned I = 0, N = Record.size(); I != N; ++I) ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I])); break; case VTABLE_USES: if (Record.size() % 3 != 0) { Error("Invalid VTABLE_USES record"); return Failure; } // Later tables overwrite earlier ones. // FIXME: Modules will have some trouble with this. This is clearly not // the right way to do this. VTableUses.clear(); for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) { VTableUses.push_back(getGlobalDeclID(F, Record[Idx++])); VTableUses.push_back( ReadSourceLocation(F, Record, Idx).getRawEncoding()); VTableUses.push_back(Record[Idx++]); } break; case PENDING_IMPLICIT_INSTANTIATIONS: if (PendingInstantiations.size() % 2 != 0) { Error("Invalid existing PendingInstantiations"); return Failure; } if (Record.size() % 2 != 0) { Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); return Failure; } for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++])); PendingInstantiations.push_back( ReadSourceLocation(F, Record, I).getRawEncoding()); } break; case SEMA_DECL_REFS: if (Record.size() != 3) { Error("Invalid SEMA_DECL_REFS block"); return Failure; } for (unsigned I = 0, N = Record.size(); I != N; ++I) SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; case PPD_ENTITIES_OFFSETS: { F.PreprocessedEntityOffsets = (const PPEntityOffset *)Blob.data(); assert(Blob.size() % sizeof(PPEntityOffset) == 0); F.NumPreprocessedEntities = Blob.size() / sizeof(PPEntityOffset); unsigned LocalBasePreprocessedEntityID = Record[0]; unsigned StartingID; if (!PP.getPreprocessingRecord()) PP.createPreprocessingRecord(); if (!PP.getPreprocessingRecord()->getExternalSource()) PP.getPreprocessingRecord()->SetExternalSource(*this); StartingID = PP.getPreprocessingRecord() ->allocateLoadedEntities(F.NumPreprocessedEntities); F.BasePreprocessedEntityID = StartingID; if (F.NumPreprocessedEntities > 0) { // Introduce the global -> local mapping for preprocessed entities in // this module. GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F)); // Introduce the local -> global mapping for preprocessed entities in // this module. F.PreprocessedEntityRemap.insertOrReplace( std::make_pair(LocalBasePreprocessedEntityID, F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID)); } break; } case DECL_UPDATE_OFFSETS: { if (Record.size() % 2 != 0) { Error("invalid DECL_UPDATE_OFFSETS block in AST file"); return Failure; } for (unsigned I = 0, N = Record.size(); I != N; I += 2) { GlobalDeclID ID = getGlobalDeclID(F, Record[I]); DeclUpdateOffsets[ID].push_back(std::make_pair(&F, Record[I + 1])); // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) PendingUpdateRecords.push_back(std::make_pair(ID, D)); } break; } case OBJC_CATEGORIES_MAP: { if (F.LocalNumObjCCategoriesInMap != 0) { Error("duplicate OBJC_CATEGORIES_MAP record in AST file"); return Failure; } F.LocalNumObjCCategoriesInMap = Record[0]; F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data(); break; } case OBJC_CATEGORIES: F.ObjCCategories.swap(Record); break; case CUDA_SPECIAL_DECL_REFS: // Later tables overwrite earlier ones. // FIXME: Modules will have trouble with this. CUDASpecialDeclRefs.clear(); for (unsigned I = 0, N = Record.size(); I != N; ++I) CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; case HEADER_SEARCH_TABLE: { F.HeaderFileInfoTableData = Blob.data(); F.LocalNumHeaderFileInfos = Record[1]; if (Record[0]) { F.HeaderFileInfoTable = HeaderFileInfoLookupTable::Create( (const unsigned char *)F.HeaderFileInfoTableData + Record[0], (const unsigned char *)F.HeaderFileInfoTableData, HeaderFileInfoTrait(*this, F, &PP.getHeaderSearchInfo(), Blob.data() + Record[2])); PP.getHeaderSearchInfo().SetExternalSource(this); if (!PP.getHeaderSearchInfo().getExternalLookup()) PP.getHeaderSearchInfo().SetExternalLookup(this); } break; } case FP_PRAGMA_OPTIONS: // Later tables overwrite earlier ones. FPPragmaOptions.swap(Record); break; case OPENCL_EXTENSIONS: for (unsigned I = 0, E = Record.size(); I != E; ) { auto Name = ReadString(Record, I); auto &Opt = OpenCLExtensions.OptMap[Name]; Opt.Supported = Record[I++] != 0; Opt.Enabled = Record[I++] != 0; Opt.Avail = Record[I++]; Opt.Core = Record[I++]; } break; case OPENCL_EXTENSION_TYPES: for (unsigned I = 0, E = Record.size(); I != E;) { auto TypeID = static_cast<::TypeID>(Record[I++]); auto *Type = GetType(TypeID).getTypePtr(); auto NumExt = static_cast(Record[I++]); for (unsigned II = 0; II != NumExt; ++II) { auto Ext = ReadString(Record, I); OpenCLTypeExtMap[Type].insert(Ext); } } break; case OPENCL_EXTENSION_DECLS: for (unsigned I = 0, E = Record.size(); I != E;) { auto DeclID = static_cast<::DeclID>(Record[I++]); auto *Decl = GetDecl(DeclID); auto NumExt = static_cast(Record[I++]); for (unsigned II = 0; II != NumExt; ++II) { auto Ext = ReadString(Record, I); OpenCLDeclExtMap[Decl].insert(Ext); } } break; case TENTATIVE_DEFINITIONS: for (unsigned I = 0, N = Record.size(); I != N; ++I) TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I])); break; case KNOWN_NAMESPACES: for (unsigned I = 0, N = Record.size(); I != N; ++I) KnownNamespaces.push_back(getGlobalDeclID(F, Record[I])); break; case UNDEFINED_BUT_USED: if (UndefinedButUsed.size() % 2 != 0) { Error("Invalid existing UndefinedButUsed"); return Failure; } if (Record.size() % 2 != 0) { Error("invalid undefined-but-used record"); return Failure; } for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++])); UndefinedButUsed.push_back( ReadSourceLocation(F, Record, I).getRawEncoding()); } break; case DELETE_EXPRS_TO_ANALYZE: for (unsigned I = 0, N = Record.size(); I != N;) { DelayedDeleteExprs.push_back(getGlobalDeclID(F, Record[I++])); const uint64_t Count = Record[I++]; DelayedDeleteExprs.push_back(Count); for (uint64_t C = 0; C < Count; ++C) { DelayedDeleteExprs.push_back(ReadSourceLocation(F, Record, I).getRawEncoding()); bool IsArrayForm = Record[I++] == 1; DelayedDeleteExprs.push_back(IsArrayForm); } } break; case IMPORTED_MODULES: { if (!F.isModule()) { // If we aren't loading a module (which has its own exports), make // all of the imported modules visible. // FIXME: Deal with macros-only imports. for (unsigned I = 0, N = Record.size(); I != N; /**/) { unsigned GlobalID = getGlobalSubmoduleID(F, Record[I++]); SourceLocation Loc = ReadSourceLocation(F, Record, I); if (GlobalID) { ImportedModules.push_back(ImportedSubmodule(GlobalID, Loc)); if (DeserializationListener) DeserializationListener->ModuleImportRead(GlobalID, Loc); } } } break; } case MACRO_OFFSET: { if (F.LocalNumMacros != 0) { Error("duplicate MACRO_OFFSET record in AST file"); return Failure; } F.MacroOffsets = (const uint32_t *)Blob.data(); F.LocalNumMacros = Record[0]; unsigned LocalBaseMacroID = Record[1]; F.BaseMacroID = getTotalNumMacros(); if (F.LocalNumMacros > 0) { // Introduce the global -> local mapping for macros within this module. GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F)); // Introduce the local -> global mapping for macros within this module. F.MacroRemap.insertOrReplace( std::make_pair(LocalBaseMacroID, F.BaseMacroID - LocalBaseMacroID)); MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros); } break; } case LATE_PARSED_TEMPLATE: { LateParsedTemplates.append(Record.begin(), Record.end()); break; } case OPTIMIZE_PRAGMA_OPTIONS: if (Record.size() != 1) { Error("invalid pragma optimize record"); return Failure; } OptimizeOffPragmaLocation = ReadSourceLocation(F, Record[0]); break; case MSSTRUCT_PRAGMA_OPTIONS: if (Record.size() != 1) { Error("invalid pragma ms_struct record"); return Failure; } PragmaMSStructState = Record[0]; break; case POINTERS_TO_MEMBERS_PRAGMA_OPTIONS: if (Record.size() != 2) { Error("invalid pragma ms_struct record"); return Failure; } PragmaMSPointersToMembersState = Record[0]; PointersToMembersPragmaLocation = ReadSourceLocation(F, Record[1]); break; case UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES: for (unsigned I = 0, N = Record.size(); I != N; ++I) UnusedLocalTypedefNameCandidates.push_back( getGlobalDeclID(F, Record[I])); break; case CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH: if (Record.size() != 1) { Error("invalid cuda pragma options record"); return Failure; } ForceCUDAHostDeviceDepth = Record[0]; break; case PACK_PRAGMA_OPTIONS: { if (Record.size() < 3) { Error("invalid pragma pack record"); return Failure; } PragmaPackCurrentValue = Record[0]; PragmaPackCurrentLocation = ReadSourceLocation(F, Record[1]); unsigned NumStackEntries = Record[2]; unsigned Idx = 3; // Reset the stack when importing a new module. PragmaPackStack.clear(); for (unsigned I = 0; I < NumStackEntries; ++I) { PragmaPackStackEntry Entry; Entry.Value = Record[Idx++]; Entry.Location = ReadSourceLocation(F, Record[Idx++]); PragmaPackStrings.push_back(ReadString(Record, Idx)); Entry.SlotLabel = PragmaPackStrings.back(); PragmaPackStack.push_back(Entry); } break; } } } } void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { assert(!F.ModuleOffsetMap.empty() && "no module offset map to read"); // Additional remapping information. const unsigned char *Data = (const unsigned char*)F.ModuleOffsetMap.data(); const unsigned char *DataEnd = Data + F.ModuleOffsetMap.size(); F.ModuleOffsetMap = StringRef(); // If we see this entry before SOURCE_LOCATION_OFFSETS, add placeholders. if (F.SLocRemap.find(0) == F.SLocRemap.end()) { F.SLocRemap.insert(std::make_pair(0U, 0)); F.SLocRemap.insert(std::make_pair(2U, 1)); } // Continuous range maps we may be updating in our module. typedef ContinuousRangeMap::Builder RemapBuilder; RemapBuilder SLocRemap(F.SLocRemap); RemapBuilder IdentifierRemap(F.IdentifierRemap); RemapBuilder MacroRemap(F.MacroRemap); RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap); RemapBuilder SubmoduleRemap(F.SubmoduleRemap); RemapBuilder SelectorRemap(F.SelectorRemap); RemapBuilder DeclRemap(F.DeclRemap); RemapBuilder TypeRemap(F.TypeRemap); while (Data < DataEnd) { // FIXME: Looking up dependency modules by filename is horrible. using namespace llvm::support; uint16_t Len = endian::readNext(Data); StringRef Name = StringRef((const char*)Data, Len); Data += Len; ModuleFile *OM = ModuleMgr.lookup(Name); if (!OM) { std::string Msg = "SourceLocation remap refers to unknown module, cannot find "; Msg.append(Name); Error(Msg); return; } uint32_t SLocOffset = endian::readNext(Data); uint32_t IdentifierIDOffset = endian::readNext(Data); uint32_t MacroIDOffset = endian::readNext(Data); uint32_t PreprocessedEntityIDOffset = endian::readNext(Data); uint32_t SubmoduleIDOffset = endian::readNext(Data); uint32_t SelectorIDOffset = endian::readNext(Data); uint32_t DeclIDOffset = endian::readNext(Data); uint32_t TypeIndexOffset = endian::readNext(Data); uint32_t None = std::numeric_limits::max(); auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset, RemapBuilder &Remap) { if (Offset != None) Remap.insert(std::make_pair(Offset, static_cast(BaseOffset - Offset))); }; mapOffset(SLocOffset, OM->SLocEntryBaseOffset, SLocRemap); mapOffset(IdentifierIDOffset, OM->BaseIdentifierID, IdentifierRemap); mapOffset(MacroIDOffset, OM->BaseMacroID, MacroRemap); mapOffset(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID, PreprocessedEntityRemap); mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap); mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap); mapOffset(DeclIDOffset, OM->BaseDeclID, DeclRemap); mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap); // Global -> local mappings. F.GlobalToLocalDeclIDs[OM] = DeclIDOffset; } } ASTReader::ASTReadResult ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities) { unsigned Idx = 0; F.ModuleMapPath = ReadPath(F, Record, Idx); if (F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule) { // For an explicitly-loaded module, we don't care whether the original // module map file exists or matches. return Success; } // Try to resolve ModuleName in the current header search context and // verify that it is found in the same module map file as we saved. If the // top-level AST file is a main file, skip this check because there is no // usable header search context. assert(!F.ModuleName.empty() && "MODULE_NAME should come before MODULE_MAP_FILE"); if (F.Kind == MK_ImplicitModule && ModuleMgr.begin()->Kind != MK_MainFile) { // An implicitly-loaded module file should have its module listed in some // module map file that we've already loaded. Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName); auto &Map = PP.getHeaderSearchInfo().getModuleMap(); const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr; if (!ModMap) { assert(ImportedBy && "top-level import should be verified"); if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) { if (auto *ASTFE = M ? M->getASTFile() : nullptr) // This module was defined by an imported (explicit) module. Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName << ASTFE->getName(); else // This module was built with a different module map. Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName << ImportedBy->FileName << F.ModuleMapPath; } return OutOfDate; } assert(M->Name == F.ModuleName && "found module with different name"); // Check the primary module map file. const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath); if (StoredModMap == nullptr || StoredModMap != ModMap) { assert(ModMap && "found module is missing module map file"); assert(ImportedBy && "top-level import should be verified"); if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Diag(diag::err_imported_module_modmap_changed) << F.ModuleName << ImportedBy->FileName << ModMap->getName() << F.ModuleMapPath; return OutOfDate; } llvm::SmallPtrSet AdditionalStoredMaps; for (unsigned I = 0, N = Record[Idx++]; I < N; ++I) { // FIXME: we should use input files rather than storing names. std::string Filename = ReadPath(F, Record, Idx); const FileEntry *F = FileMgr.getFile(Filename, false, false); if (F == nullptr) { if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Error("could not find file '" + Filename +"' referenced by AST file"); return OutOfDate; } AdditionalStoredMaps.insert(F); } // Check any additional module map files (e.g. module.private.modulemap) // that are not in the pcm. if (auto *AdditionalModuleMaps = Map.getAdditionalModuleMapFiles(M)) { for (const FileEntry *ModMap : *AdditionalModuleMaps) { // Remove files that match // Note: SmallPtrSet::erase is really remove if (!AdditionalStoredMaps.erase(ModMap)) { if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Diag(diag::err_module_different_modmap) << F.ModuleName << /*new*/0 << ModMap->getName(); return OutOfDate; } } } // Check any additional module map files that are in the pcm, but not // found in header search. Cases that match are already removed. for (const FileEntry *ModMap : AdditionalStoredMaps) { if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Diag(diag::err_module_different_modmap) << F.ModuleName << /*not new*/1 << ModMap->getName(); return OutOfDate; } } if (Listener) Listener->ReadModuleMapFile(F.ModuleMapPath); return Success; } /// \brief Move the given method to the back of the global list of methods. static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { // Find the entry for this selector in the method pool. Sema::GlobalMethodPool::iterator Known = S.MethodPool.find(Method->getSelector()); if (Known == S.MethodPool.end()) return; // Retrieve the appropriate method list. ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first : Known->second.second; bool Found = false; for (ObjCMethodList *List = &Start; List; List = List->getNext()) { if (!Found) { if (List->getMethod() == Method) { Found = true; } else { // Keep searching. continue; } } if (List->getNext()) List->setMethod(List->getNext()->getMethod()); else List->setMethod(Method); } } void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) { assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?"); for (Decl *D : Names) { bool wasHidden = D->Hidden; D->Hidden = false; if (wasHidden && SemaObj) { if (ObjCMethodDecl *Method = dyn_cast(D)) { moveMethodToBackOfGlobalList(*SemaObj, Method); } } } } void ASTReader::makeModuleVisible(Module *Mod, Module::NameVisibilityKind NameVisibility, SourceLocation ImportLoc) { llvm::SmallPtrSet Visited; SmallVector Stack; Stack.push_back(Mod); while (!Stack.empty()) { Mod = Stack.pop_back_val(); if (NameVisibility <= Mod->NameVisibility) { // This module already has this level of visibility (or greater), so // there is nothing more to do. continue; } if (!Mod->isAvailable()) { // Modules that aren't available cannot be made visible. continue; } // Update the module's name visibility. Mod->NameVisibility = NameVisibility; // If we've already deserialized any names from this module, // mark them as visible. HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod); if (Hidden != HiddenNamesMap.end()) { auto HiddenNames = std::move(*Hidden); HiddenNamesMap.erase(Hidden); makeNamesVisible(HiddenNames.second, HiddenNames.first); assert(HiddenNamesMap.find(Mod) == HiddenNamesMap.end() && "making names visible added hidden names"); } // Push any exported modules onto the stack to be marked as visible. SmallVector Exports; Mod->getExportedModules(Exports); for (SmallVectorImpl::iterator I = Exports.begin(), E = Exports.end(); I != E; ++I) { Module *Exported = *I; if (Visited.insert(Exported).second) Stack.push_back(Exported); } } } /// We've merged the definition \p MergedDef into the existing definition /// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made /// visible. void ASTReader::mergeDefinitionVisibility(NamedDecl *Def, NamedDecl *MergedDef) { // FIXME: This doesn't correctly handle the case where MergedDef is visible // in modules other than its owning module. We should instead give the // ASTContext a list of merged definitions for Def. if (Def->isHidden()) { // If MergedDef is visible or becomes visible, make the definition visible. if (!MergedDef->isHidden()) Def->Hidden = false; else if (getContext().getLangOpts().ModulesLocalVisibility) { getContext().mergeDefinitionIntoModule( Def, MergedDef->getImportedOwningModule(), /*NotifyListeners*/ false); PendingMergedDefinitionsToDeduplicate.insert(Def); } else { auto SubmoduleID = MergedDef->getOwningModuleID(); assert(SubmoduleID && "hidden definition in no module"); HiddenNamesMap[getSubmodule(SubmoduleID)].push_back(Def); } } } bool ASTReader::loadGlobalIndex() { if (GlobalIndex) return false; if (TriedLoadingGlobalIndex || !UseGlobalIndex || !Context.getLangOpts().Modules) return true; // Try to load the global index. TriedLoadingGlobalIndex = true; StringRef ModuleCachePath = getPreprocessor().getHeaderSearchInfo().getModuleCachePath(); std::pair Result = GlobalModuleIndex::readIndex(ModuleCachePath); if (!Result.first) return true; GlobalIndex.reset(Result.first); ModuleMgr.setGlobalIndex(GlobalIndex.get()); return false; } bool ASTReader::isGlobalIndexUnavailable() const { return Context.getLangOpts().Modules && UseGlobalIndex && !hasGlobalIndex() && TriedLoadingGlobalIndex; } static void updateModuleTimestamp(ModuleFile &MF) { // Overwrite the timestamp file contents so that file's mtime changes. std::string TimestampFilename = MF.getTimestampFilename(); std::error_code EC; llvm::raw_fd_ostream OS(TimestampFilename, EC, llvm::sys::fs::F_Text); if (EC) return; OS << "Timestamp file\n"; } /// \brief Given a cursor at the start of an AST file, scan ahead and drop the /// cursor into the start of the given block ID, returning false on success and /// true on failure. static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) { while (true) { llvm::BitstreamEntry Entry = Cursor.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: case llvm::BitstreamEntry::EndBlock: return true; case llvm::BitstreamEntry::Record: // Ignore top-level records. Cursor.skipRecord(Entry.ID); break; case llvm::BitstreamEntry::SubBlock: if (Entry.ID == BlockID) { if (Cursor.EnterSubBlock(BlockID)) return true; // Found it! return false; } if (Cursor.SkipBlock()) return true; } } } ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, unsigned ClientLoadCapabilities, SmallVectorImpl *Imported) { llvm::SaveAndRestore SetCurImportLocRAII(CurrentImportLoc, ImportLoc); // Defer any pending actions until we get to the end of reading the AST file. Deserializing AnASTFile(this); // Bump the generation number. unsigned PreviousGeneration = incrementGeneration(Context); unsigned NumModules = ModuleMgr.size(); SmallVector Loaded; switch (ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, /*ImportedBy=*/nullptr, Loaded, 0, 0, ASTFileSignature(), ClientLoadCapabilities)) { case Failure: case Missing: case OutOfDate: case VersionMismatch: case ConfigurationMismatch: case HadErrors: { llvm::SmallPtrSet LoadedSet; for (const ImportedModule &IM : Loaded) LoadedSet.insert(IM.Mod); ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet, Context.getLangOpts().Modules ? &PP.getHeaderSearchInfo().getModuleMap() : nullptr); // If we find that any modules are unusable, the global index is going // to be out-of-date. Just remove it. GlobalIndex.reset(); ModuleMgr.setGlobalIndex(nullptr); return ReadResult; } case Success: break; } // Here comes stuff that we only do once the entire chain is loaded. // Load the AST blocks of all of the modules that we loaded. for (SmallVectorImpl::iterator M = Loaded.begin(), MEnd = Loaded.end(); M != MEnd; ++M) { ModuleFile &F = *M->Mod; // Read the AST block. if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities)) return Result; // Read the extension blocks. while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) { if (ASTReadResult Result = ReadExtensionBlock(F)) return Result; } // Once read, set the ModuleFile bit base offset and update the size in // bits of all files we've seen. F.GlobalBitOffset = TotalModulesSizeInBits; TotalModulesSizeInBits += F.SizeInBits; GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); // Preload SLocEntries. for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) { int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; // Load it through the SourceManager and don't call ReadSLocEntry() // directly because the entry may have already been loaded in which case // calling ReadSLocEntry() directly would trigger an assertion in // SourceManager. SourceMgr.getLoadedSLocEntryByID(Index); } // Map the original source file ID into the ID space of the current // compilation. if (F.OriginalSourceFileID.isValid()) { F.OriginalSourceFileID = FileID::get( F.SLocEntryBaseID + F.OriginalSourceFileID.getOpaqueValue() - 1); } // Preload all the pending interesting identifiers by marking them out of // date. for (auto Offset : F.PreloadIdentifierOffsets) { const unsigned char *Data = reinterpret_cast( F.IdentifierTableData + Offset); ASTIdentifierLookupTrait Trait(*this, F); auto KeyDataLen = Trait.ReadKeyDataLength(Data); auto Key = Trait.ReadKey(Data, KeyDataLen.first); auto &II = PP.getIdentifierTable().getOwn(Key); II.setOutOfDate(true); // Mark this identifier as being from an AST file so that we can track // whether we need to serialize it. markIdentifierFromAST(*this, II); // Associate the ID with the identifier so that the writer can reuse it. auto ID = Trait.ReadIdentifierID(Data + KeyDataLen.first); SetIdentifierInfo(ID, &II); } } // Setup the import locations and notify the module manager that we've // committed to these module files. for (SmallVectorImpl::iterator M = Loaded.begin(), MEnd = Loaded.end(); M != MEnd; ++M) { ModuleFile &F = *M->Mod; ModuleMgr.moduleFileAccepted(&F); // Set the import location. F.DirectImportLoc = ImportLoc; // FIXME: We assume that locations from PCH / preamble do not need // any translation. if (!M->ImportedBy) F.ImportLoc = M->ImportLoc; else F.ImportLoc = TranslateSourceLocation(*M->ImportedBy, M->ImportLoc); } if (!Context.getLangOpts().CPlusPlus || (Type != MK_ImplicitModule && Type != MK_ExplicitModule && Type != MK_PrebuiltModule)) { // Mark all of the identifiers in the identifier table as being out of date, // so that various accessors know to check the loaded modules when the // identifier is used. // // For C++ modules, we don't need information on many identifiers (just // those that provide macros or are poisoned), so we mark all of // the interesting ones via PreloadIdentifierOffsets. for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), IdEnd = PP.getIdentifierTable().end(); Id != IdEnd; ++Id) Id->second->setOutOfDate(true); } // Mark selectors as out of date. for (auto Sel : SelectorGeneration) SelectorOutOfDate[Sel.first] = true; // Resolve any unresolved module exports. for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) { UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I]; SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID); Module *ResolvedMod = getSubmodule(GlobalID); switch (Unresolved.Kind) { case UnresolvedModuleRef::Conflict: if (ResolvedMod) { Module::Conflict Conflict; Conflict.Other = ResolvedMod; Conflict.Message = Unresolved.String.str(); Unresolved.Mod->Conflicts.push_back(Conflict); } continue; case UnresolvedModuleRef::Import: if (ResolvedMod) Unresolved.Mod->Imports.insert(ResolvedMod); continue; case UnresolvedModuleRef::Export: if (ResolvedMod || Unresolved.IsWildcard) Unresolved.Mod->Exports.push_back( Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); continue; } } UnresolvedModuleRefs.clear(); if (Imported) Imported->append(ImportedModules.begin(), ImportedModules.end()); // FIXME: How do we load the 'use'd modules? They may not be submodules. // Might be unnecessary as use declarations are only used to build the // module itself. InitializeContext(); if (SemaObj) UpdateSema(); if (DeserializationListener) DeserializationListener->ReaderInitialized(this); ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); if (PrimaryModule.OriginalSourceFileID.isValid()) { // If this AST file is a precompiled preamble, then set the // preamble file ID of the source manager to the file source file // from which the preamble was built. if (Type == MK_Preamble) { SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID); } else if (Type == MK_MainFile) { SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID); } } // For any Objective-C class definitions we have already loaded, make sure // that we load any additional categories. for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) { loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(), ObjCClassesLoaded[I], PreviousGeneration); } if (PP.getHeaderSearchInfo() .getHeaderSearchOpts() .ModulesValidateOncePerBuildSession) { // Now we are certain that the module and all modules it depends on are // up to date. Create or update timestamp files for modules that are // located in the module cache (not for PCH files that could be anywhere // in the filesystem). for (unsigned I = 0, N = Loaded.size(); I != N; ++I) { ImportedModule &M = Loaded[I]; if (M.Mod->Kind == MK_ImplicitModule) { updateModuleTimestamp(*M.Mod); } } } return Success; } static ASTFileSignature readASTFileSignature(StringRef PCH); /// \brief Whether \p Stream starts with the AST/PCH file magic number 'CPCH'. static bool startsWithASTFileMagic(BitstreamCursor &Stream) { return Stream.canSkipToPos(4) && Stream.Read(8) == 'C' && Stream.Read(8) == 'P' && Stream.Read(8) == 'C' && Stream.Read(8) == 'H'; } static unsigned moduleKindForDiagnostic(ModuleKind Kind) { switch (Kind) { case MK_PCH: return 0; // PCH case MK_ImplicitModule: case MK_ExplicitModule: case MK_PrebuiltModule: return 1; // module case MK_MainFile: case MK_Preamble: return 2; // main source file } llvm_unreachable("unknown module kind"); } ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, SmallVectorImpl &Loaded, off_t ExpectedSize, time_t ExpectedModTime, ASTFileSignature ExpectedSignature, unsigned ClientLoadCapabilities) { ModuleFile *M; std::string ErrorStr; ModuleManager::AddModuleResult AddResult = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy, getGeneration(), ExpectedSize, ExpectedModTime, ExpectedSignature, readASTFileSignature, M, ErrorStr); switch (AddResult) { case ModuleManager::AlreadyLoaded: return Success; case ModuleManager::NewlyLoaded: // Load module file below. break; case ModuleManager::Missing: // The module file was missing; if the client can handle that, return // it. if (ClientLoadCapabilities & ARR_Missing) return Missing; // Otherwise, return an error. Diag(diag::err_module_file_not_found) << moduleKindForDiagnostic(Type) << FileName << !ErrorStr.empty() << ErrorStr; return Failure; case ModuleManager::OutOfDate: // We couldn't load the module file because it is out-of-date. If the // client can handle out-of-date, return it. if (ClientLoadCapabilities & ARR_OutOfDate) return OutOfDate; // Otherwise, return an error. Diag(diag::err_module_file_out_of_date) << moduleKindForDiagnostic(Type) << FileName << !ErrorStr.empty() << ErrorStr; return Failure; } assert(M && "Missing module file"); // FIXME: This seems rather a hack. Should CurrentDir be part of the // module? if (FileName != "-") { CurrentDir = llvm::sys::path::parent_path(FileName); if (CurrentDir.empty()) CurrentDir = "."; } ModuleFile &F = *M; BitstreamCursor &Stream = F.Stream; Stream = BitstreamCursor(PCHContainerRdr.ExtractPCH(*F.Buffer)); F.SizeInBits = F.Buffer->getBufferSize() * 8; // Sniff for the signature. if (!startsWithASTFileMagic(Stream)) { Diag(diag::err_module_file_invalid) << moduleKindForDiagnostic(Type) << FileName; return Failure; } // This is used for compatibility with older PCH formats. bool HaveReadControlBlock = false; while (true) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: case llvm::BitstreamEntry::Record: case llvm::BitstreamEntry::EndBlock: Error("invalid record at top-level of AST file"); return Failure; case llvm::BitstreamEntry::SubBlock: break; } switch (Entry.ID) { case CONTROL_BLOCK_ID: HaveReadControlBlock = true; switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) { case Success: // Check that we didn't try to load a non-module AST file as a module. // // FIXME: Should we also perform the converse check? Loading a module as // a PCH file sort of works, but it's a bit wonky. if ((Type == MK_ImplicitModule || Type == MK_ExplicitModule || Type == MK_PrebuiltModule) && F.ModuleName.empty()) { auto Result = (Type == MK_ImplicitModule) ? OutOfDate : Failure; if (Result != OutOfDate || (ClientLoadCapabilities & ARR_OutOfDate) == 0) Diag(diag::err_module_file_not_module) << FileName; return Result; } break; case Failure: return Failure; case Missing: return Missing; case OutOfDate: return OutOfDate; case VersionMismatch: return VersionMismatch; case ConfigurationMismatch: return ConfigurationMismatch; case HadErrors: return HadErrors; } break; case AST_BLOCK_ID: if (!HaveReadControlBlock) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) Diag(diag::err_pch_version_too_old); return VersionMismatch; } // Record that we've loaded this module. Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc)); return Success; case UNHASHED_CONTROL_BLOCK_ID: // This block is handled using look-ahead during ReadControlBlock. We // shouldn't get here! Error("malformed block record in AST file"); return Failure; default: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); return Failure; } break; } } return Success; } ASTReader::ASTReadResult ASTReader::readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy, unsigned ClientLoadCapabilities) { const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule; ASTReadResult Result = readUnhashedControlBlockImpl( &F, F.Data, ClientLoadCapabilities, AllowCompatibleConfigurationMismatch, Listener.get(), WasImportedBy ? false : HSOpts.ModulesValidateDiagnosticOptions); // If F was directly imported by another module, it's implicitly validated by // the importing module. if (DisableValidation || WasImportedBy || (AllowConfigurationMismatch && Result == ConfigurationMismatch)) return Success; if (Result == Failure) { Error("malformed block record in AST file"); return Failure; } if (Result == OutOfDate && F.Kind == MK_ImplicitModule) { // If this module has already been finalized in the PCMCache, we're stuck // with it; we can only load a single version of each module. // // This can happen when a module is imported in two contexts: in one, as a // user module; in another, as a system module (due to an import from // another module marked with the [system] flag). It usually indicates a // bug in the module map: this module should also be marked with [system]. // // If -Wno-system-headers (the default), and the first import is as a // system module, then validation will fail during the as-user import, // since -Werror flags won't have been validated. However, it's reasonable // to treat this consistently as a system module. // // If -Wsystem-headers, the PCM on disk was built with // -Wno-system-headers, and the first import is as a user module, then // validation will fail during the as-system import since the PCM on disk // doesn't guarantee that -Werror was respected. However, the -Werror // flags were checked during the initial as-user import. if (PCMCache.isBufferFinal(F.FileName)) { Diag(diag::warn_module_system_bit_conflict) << F.FileName; return Success; } } return Result; } ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl( ModuleFile *F, llvm::StringRef StreamData, unsigned ClientLoadCapabilities, bool AllowCompatibleConfigurationMismatch, ASTReaderListener *Listener, bool ValidateDiagnosticOptions) { // Initialize a stream. BitstreamCursor Stream(StreamData); // Sniff for the signature. if (!startsWithASTFileMagic(Stream)) return Failure; // Scan for the UNHASHED_CONTROL_BLOCK_ID block. if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID)) return Failure; // Read all of the records in the options block. RecordData Record; ASTReadResult Result = Success; while (1) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: case llvm::BitstreamEntry::SubBlock: return Failure; case llvm::BitstreamEntry::EndBlock: return Result; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read and process a record. Record.clear(); switch ( (UnhashedControlBlockRecordTypes)Stream.readRecord(Entry.ID, Record)) { case SIGNATURE: { if (F) std::copy(Record.begin(), Record.end(), F->Signature.data()); break; } case DIAGNOSTIC_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; if (Listener && ValidateDiagnosticOptions && !AllowCompatibleConfigurationMismatch && ParseDiagnosticOptions(Record, Complain, *Listener)) Result = OutOfDate; // Don't return early. Read the signature. break; } case DIAG_PRAGMA_MAPPINGS: if (!F) break; if (F->PragmaDiagMappings.empty()) F->PragmaDiagMappings.swap(Record); else F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(), Record.begin(), Record.end()); break; } } } /// Parse a record and blob containing module file extension metadata. static bool parseModuleFileExtensionMetadata( const SmallVectorImpl &Record, StringRef Blob, ModuleFileExtensionMetadata &Metadata) { if (Record.size() < 4) return true; Metadata.MajorVersion = Record[0]; Metadata.MinorVersion = Record[1]; unsigned BlockNameLen = Record[2]; unsigned UserInfoLen = Record[3]; if (BlockNameLen + UserInfoLen > Blob.size()) return true; Metadata.BlockName = std::string(Blob.data(), Blob.data() + BlockNameLen); Metadata.UserInfo = std::string(Blob.data() + BlockNameLen, Blob.data() + BlockNameLen + UserInfoLen); return false; } ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { BitstreamCursor &Stream = F.Stream; RecordData Record; while (true) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: if (Stream.SkipBlock()) return Failure; continue; case llvm::BitstreamEntry::EndBlock: return Success; case llvm::BitstreamEntry::Error: return HadErrors; case llvm::BitstreamEntry::Record: break; } Record.clear(); StringRef Blob; unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); switch (RecCode) { case EXTENSION_METADATA: { ModuleFileExtensionMetadata Metadata; if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) return Failure; // Find a module file extension with this block name. auto Known = ModuleFileExtensions.find(Metadata.BlockName); if (Known == ModuleFileExtensions.end()) break; // Form a reader. if (auto Reader = Known->second->createExtensionReader(Metadata, *this, F, Stream)) { F.ExtensionReaders.push_back(std::move(Reader)); } break; } } } return Success; } void ASTReader::InitializeContext() { // If there's a listener, notify them that we "read" the translation unit. if (DeserializationListener) DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, Context.getTranslationUnitDecl()); // FIXME: Find a better way to deal with collisions between these // built-in types. Right now, we just ignore the problem. // Load the special types. if (SpecialTypes.size() >= NumSpecialTypeIDs) { if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) { if (!Context.CFConstantStringTypeDecl) Context.setCFConstantStringType(GetType(String)); } if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) { QualType FileType = GetType(File); if (FileType.isNull()) { Error("FILE type is NULL"); return; } if (!Context.FILEDecl) { if (const TypedefType *Typedef = FileType->getAs()) Context.setFILEDecl(Typedef->getDecl()); else { const TagType *Tag = FileType->getAs(); if (!Tag) { Error("Invalid FILE type in AST file"); return; } Context.setFILEDecl(Tag->getDecl()); } } } if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) { QualType Jmp_bufType = GetType(Jmp_buf); if (Jmp_bufType.isNull()) { Error("jmp_buf type is NULL"); return; } if (!Context.jmp_bufDecl) { if (const TypedefType *Typedef = Jmp_bufType->getAs()) Context.setjmp_bufDecl(Typedef->getDecl()); else { const TagType *Tag = Jmp_bufType->getAs(); if (!Tag) { Error("Invalid jmp_buf type in AST file"); return; } Context.setjmp_bufDecl(Tag->getDecl()); } } } if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) { QualType Sigjmp_bufType = GetType(Sigjmp_buf); if (Sigjmp_bufType.isNull()) { Error("sigjmp_buf type is NULL"); return; } if (!Context.sigjmp_bufDecl) { if (const TypedefType *Typedef = Sigjmp_bufType->getAs()) Context.setsigjmp_bufDecl(Typedef->getDecl()); else { const TagType *Tag = Sigjmp_bufType->getAs(); assert(Tag && "Invalid sigjmp_buf type in AST file"); Context.setsigjmp_bufDecl(Tag->getDecl()); } } } if (unsigned ObjCIdRedef = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) { if (Context.ObjCIdRedefinitionType.isNull()) Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef); } if (unsigned ObjCClassRedef = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) { if (Context.ObjCClassRedefinitionType.isNull()) Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef); } if (unsigned ObjCSelRedef = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) { if (Context.ObjCSelRedefinitionType.isNull()) Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef); } if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) { QualType Ucontext_tType = GetType(Ucontext_t); if (Ucontext_tType.isNull()) { Error("ucontext_t type is NULL"); return; } if (!Context.ucontext_tDecl) { if (const TypedefType *Typedef = Ucontext_tType->getAs()) Context.setucontext_tDecl(Typedef->getDecl()); else { const TagType *Tag = Ucontext_tType->getAs(); assert(Tag && "Invalid ucontext_t type in AST file"); Context.setucontext_tDecl(Tag->getDecl()); } } } } ReadPragmaDiagnosticMappings(Context.getDiagnostics()); // If there were any CUDA special declarations, deserialize them. if (!CUDASpecialDeclRefs.empty()) { assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!"); Context.setcudaConfigureCallDecl( cast(GetDecl(CUDASpecialDeclRefs[0]))); } // Re-export any modules that were imported by a non-module AST file. // FIXME: This does not make macro-only imports visible again. for (auto &Import : ImportedModules) { if (Module *Imported = getSubmodule(Import.ID)) { makeModuleVisible(Imported, Module::AllVisible, /*ImportLoc=*/Import.ImportLoc); if (Import.ImportLoc.isValid()) PP.makeModuleVisible(Imported, Import.ImportLoc); // FIXME: should we tell Sema to make the module visible too? } } ImportedModules.clear(); } void ASTReader::finalizeForWriting() { // Nothing to do for now. } /// \brief Reads and return the signature record from \p PCH's control block, or /// else returns 0. static ASTFileSignature readASTFileSignature(StringRef PCH) { BitstreamCursor Stream(PCH); if (!startsWithASTFileMagic(Stream)) return ASTFileSignature(); // Scan for the UNHASHED_CONTROL_BLOCK_ID block. if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID)) return ASTFileSignature(); // Scan for SIGNATURE inside the diagnostic options block. ASTReader::RecordData Record; while (true) { llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); if (Entry.Kind != llvm::BitstreamEntry::Record) return ASTFileSignature(); Record.clear(); StringRef Blob; if (SIGNATURE == Stream.readRecord(Entry.ID, Record, &Blob)) return {{{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2], (uint32_t)Record[3], (uint32_t)Record[4]}}}; } } /// \brief Retrieve the name of the original source file name /// directly from the AST file, without actually loading the AST /// file. std::string ASTReader::getOriginalSourceFile( const std::string &ASTFileName, FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr, DiagnosticsEngine &Diags) { // Open the AST file. auto Buffer = FileMgr.getBufferForFile(ASTFileName); if (!Buffer) { Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << Buffer.getError().message(); return std::string(); } // Initialize the stream BitstreamCursor Stream(PCHContainerRdr.ExtractPCH(**Buffer)); // Sniff for the signature. if (!startsWithASTFileMagic(Stream)) { Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName; return std::string(); } // Scan for the CONTROL_BLOCK_ID block. if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } // Scan for ORIGINAL_FILE inside the control block. RecordData Record; while (true) { llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); if (Entry.Kind == llvm::BitstreamEntry::EndBlock) return std::string(); if (Entry.Kind != llvm::BitstreamEntry::Record) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } Record.clear(); StringRef Blob; if (Stream.readRecord(Entry.ID, Record, &Blob) == ORIGINAL_FILE) return Blob.str(); } } namespace { class SimplePCHValidator : public ASTReaderListener { const LangOptions &ExistingLangOpts; const TargetOptions &ExistingTargetOpts; const PreprocessorOptions &ExistingPPOpts; std::string ExistingModuleCachePath; FileManager &FileMgr; public: SimplePCHValidator(const LangOptions &ExistingLangOpts, const TargetOptions &ExistingTargetOpts, const PreprocessorOptions &ExistingPPOpts, StringRef ExistingModuleCachePath, FileManager &FileMgr) : ExistingLangOpts(ExistingLangOpts), ExistingTargetOpts(ExistingTargetOpts), ExistingPPOpts(ExistingPPOpts), ExistingModuleCachePath(ExistingModuleCachePath), FileMgr(FileMgr) { } bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) override { return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr, AllowCompatibleDifferences); } bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) override { return checkTargetOptions(ExistingTargetOpts, TargetOpts, nullptr, AllowCompatibleDifferences); } bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) override { return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath, ExistingModuleCachePath, nullptr, ExistingLangOpts); } bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain, std::string &SuggestedPredefines) override { return checkPreprocessorOptions(ExistingPPOpts, PPOpts, nullptr, FileMgr, SuggestedPredefines, ExistingLangOpts); } }; } // end anonymous namespace bool ASTReader::readASTFileControlBlock( StringRef Filename, FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions) { // Open the AST file. // FIXME: This allows use of the VFS; we do not allow use of the // VFS when actually loading a module. auto Buffer = FileMgr.getBufferForFile(Filename); if (!Buffer) { return true; } // Initialize the stream StringRef Bytes = PCHContainerRdr.ExtractPCH(**Buffer); BitstreamCursor Stream(Bytes); // Sniff for the signature. if (!startsWithASTFileMagic(Stream)) return true; // Scan for the CONTROL_BLOCK_ID block. if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) return true; bool NeedsInputFiles = Listener.needsInputFileVisitation(); bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation(); bool NeedsImports = Listener.needsImportVisitation(); BitstreamCursor InputFilesCursor; RecordData Record; std::string ModuleDir; bool DoneWithControlBlock = false; while (!DoneWithControlBlock) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: { switch (Entry.ID) { case OPTIONS_BLOCK_ID: { std::string IgnoredSuggestedPredefines; if (ReadOptionsBlock(Stream, ARR_ConfigurationMismatch | ARR_OutOfDate, /*AllowCompatibleConfigurationMismatch*/ false, Listener, IgnoredSuggestedPredefines) != Success) return true; break; } case INPUT_FILES_BLOCK_ID: InputFilesCursor = Stream; if (Stream.SkipBlock() || (NeedsInputFiles && ReadBlockAbbrevs(InputFilesCursor, INPUT_FILES_BLOCK_ID))) return true; break; default: if (Stream.SkipBlock()) return true; break; } continue; } case llvm::BitstreamEntry::EndBlock: DoneWithControlBlock = true; break; case llvm::BitstreamEntry::Error: return true; case llvm::BitstreamEntry::Record: break; } if (DoneWithControlBlock) break; Record.clear(); StringRef Blob; unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); switch ((ControlRecordTypes)RecCode) { case METADATA: { if (Record[0] != VERSION_MAJOR) return true; if (Listener.ReadFullVersionInformation(Blob)) return true; break; } case MODULE_NAME: Listener.ReadModuleName(Blob); break; case MODULE_DIRECTORY: ModuleDir = Blob; break; case MODULE_MAP_FILE: { unsigned Idx = 0; auto Path = ReadString(Record, Idx); ResolveImportedPath(Path, ModuleDir); Listener.ReadModuleMapFile(Path); break; } case INPUT_FILE_OFFSETS: { if (!NeedsInputFiles) break; unsigned NumInputFiles = Record[0]; unsigned NumUserFiles = Record[1]; const uint64_t *InputFileOffs = (const uint64_t *)Blob.data(); for (unsigned I = 0; I != NumInputFiles; ++I) { // Go find this input file. bool isSystemFile = I >= NumUserFiles; if (isSystemFile && !NeedsSystemInputFiles) break; // the rest are system input files BitstreamCursor &Cursor = InputFilesCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(InputFileOffs[I]); unsigned Code = Cursor.ReadCode(); RecordData Record; StringRef Blob; bool shouldContinue = false; switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) { case INPUT_FILE: bool Overridden = static_cast(Record[3]); std::string Filename = Blob; ResolveImportedPath(Filename, ModuleDir); shouldContinue = Listener.visitInputFile( Filename, isSystemFile, Overridden, /*IsExplicitModule*/false); break; } if (!shouldContinue) break; } break; } case IMPORTS: { if (!NeedsImports) break; unsigned Idx = 0, N = Record.size(); while (Idx < N) { // Read information about the AST file. Idx += 5; // ImportLoc, Size, ModTime, Signature std::string Filename = ReadString(Record, Idx); ResolveImportedPath(Filename, ModuleDir); Listener.visitImport(Filename); } break; } default: // No other validation to perform. break; } } // Look for module file extension blocks, if requested. if (FindModuleFileExtensions) { BitstreamCursor SavedStream = Stream; while (!SkipCursorToBlock(Stream, EXTENSION_BLOCK_ID)) { bool DoneWithExtensionBlock = false; while (!DoneWithExtensionBlock) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: if (Stream.SkipBlock()) return true; continue; case llvm::BitstreamEntry::EndBlock: DoneWithExtensionBlock = true; continue; case llvm::BitstreamEntry::Error: return true; case llvm::BitstreamEntry::Record: break; } Record.clear(); StringRef Blob; unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); switch (RecCode) { case EXTENSION_METADATA: { ModuleFileExtensionMetadata Metadata; if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) return true; Listener.readModuleFileExtension(Metadata); break; } } } } Stream = SavedStream; } // Scan for the UNHASHED_CONTROL_BLOCK_ID block. if (readUnhashedControlBlockImpl( nullptr, Bytes, ARR_ConfigurationMismatch | ARR_OutOfDate, /*AllowCompatibleConfigurationMismatch*/ false, &Listener, ValidateDiagnosticOptions) != Success) return true; return false; } bool ASTReader::isAcceptableASTFile(StringRef Filename, FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr, const LangOptions &LangOpts, const TargetOptions &TargetOpts, const PreprocessorOptions &PPOpts, StringRef ExistingModuleCachePath) { SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, ExistingModuleCachePath, FileMgr); return !readASTFileControlBlock(Filename, FileMgr, PCHContainerRdr, /*FindModuleFileExtensions=*/false, validator, /*ValidateDiagnosticOptions=*/true); } ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // Enter the submodule block. if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) { Error("malformed submodule block record in AST file"); return Failure; } ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); bool First = true; Module *CurrentModule = nullptr; Module::ModuleKind ModuleKind = Module::ModuleMapModule; RecordData Record; while (true) { llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return Failure; case llvm::BitstreamEntry::EndBlock: return Success; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read a record. StringRef Blob; Record.clear(); auto Kind = F.Stream.readRecord(Entry.ID, Record, &Blob); if ((Kind == SUBMODULE_METADATA) != First) { Error("submodule metadata record should be at beginning of block"); return Failure; } First = false; // Submodule information is only valid if we have a current module. // FIXME: Should we error on these cases? if (!CurrentModule && Kind != SUBMODULE_METADATA && Kind != SUBMODULE_DEFINITION) continue; switch (Kind) { default: // Default behavior: ignore. break; case SUBMODULE_DEFINITION: { if (Record.size() < 8) { Error("malformed module definition"); return Failure; } StringRef Name = Blob; unsigned Idx = 0; SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]); SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]); bool IsFramework = Record[Idx++]; bool IsExplicit = Record[Idx++]; bool IsSystem = Record[Idx++]; bool IsExternC = Record[Idx++]; bool InferSubmodules = Record[Idx++]; bool InferExplicitSubmodules = Record[Idx++]; bool InferExportWildcard = Record[Idx++]; bool ConfigMacrosExhaustive = Record[Idx++]; Module *ParentModule = nullptr; if (Parent) ParentModule = getSubmodule(Parent); // Retrieve this (sub)module from the module map, creating it if // necessary. CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit) .first; // FIXME: set the definition loc for CurrentModule, or call // ModMap.setInferredModuleAllowedBy() SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS; if (GlobalIndex >= SubmodulesLoaded.size() || SubmodulesLoaded[GlobalIndex]) { Error("too many submodules"); return Failure; } if (!ParentModule) { if (const FileEntry *CurFile = CurrentModule->getASTFile()) { if (CurFile != F.File) { if (!Diags.isDiagnosticInFlight()) { Diag(diag::err_module_file_conflict) << CurrentModule->getTopLevelModuleName() << CurFile->getName() << F.File->getName(); } return Failure; } } CurrentModule->setASTFile(F.File); } CurrentModule->Kind = ModuleKind; CurrentModule->Signature = F.Signature; CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; CurrentModule->IsExternC = IsExternC; CurrentModule->InferSubmodules = InferSubmodules; CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; CurrentModule->InferExportWildcard = InferExportWildcard; CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive; if (DeserializationListener) DeserializationListener->ModuleRead(GlobalID, CurrentModule); SubmodulesLoaded[GlobalIndex] = CurrentModule; // Clear out data that will be replaced by what is in the module file. CurrentModule->LinkLibraries.clear(); CurrentModule->ConfigMacros.clear(); CurrentModule->UnresolvedConflicts.clear(); CurrentModule->Conflicts.clear(); // The module is available unless it's missing a requirement; relevant // requirements will be (re-)added by SUBMODULE_REQUIRES records. // Missing headers that were present when the module was built do not // make it unavailable -- if we got this far, this must be an explicitly // imported module file. CurrentModule->Requirements.clear(); CurrentModule->MissingHeaders.clear(); CurrentModule->IsMissingRequirement = ParentModule && ParentModule->IsMissingRequirement; CurrentModule->IsAvailable = !CurrentModule->IsMissingRequirement; break; } case SUBMODULE_UMBRELLA_HEADER: { std::string Filename = Blob; ResolveImportedPath(F, Filename); if (auto *Umbrella = PP.getFileManager().getFile(Filename)) { if (!CurrentModule->getUmbrellaHeader()) ModMap.setUmbrellaHeader(CurrentModule, Umbrella, Blob); else if (CurrentModule->getUmbrellaHeader().Entry != Umbrella) { if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Error("mismatched umbrella headers in submodule"); return OutOfDate; } } break; } case SUBMODULE_HEADER: case SUBMODULE_EXCLUDED_HEADER: case SUBMODULE_PRIVATE_HEADER: // We lazily associate headers with their modules via the HeaderInfo table. // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead // of complete filenames or remove it entirely. break; case SUBMODULE_TEXTUAL_HEADER: case SUBMODULE_PRIVATE_TEXTUAL_HEADER: // FIXME: Textual headers are not marked in the HeaderInfo table. Load // them here. break; case SUBMODULE_TOPHEADER: { CurrentModule->addTopHeaderFilename(Blob); break; } case SUBMODULE_UMBRELLA_DIR: { std::string Dirname = Blob; ResolveImportedPath(F, Dirname); if (auto *Umbrella = PP.getFileManager().getDirectory(Dirname)) { if (!CurrentModule->getUmbrellaDir()) ModMap.setUmbrellaDir(CurrentModule, Umbrella, Blob); else if (CurrentModule->getUmbrellaDir().Entry != Umbrella) { if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Error("mismatched umbrella directories in submodule"); return OutOfDate; } } break; } case SUBMODULE_METADATA: { F.BaseSubmoduleID = getTotalNumSubmodules(); F.LocalNumSubmodules = Record[0]; unsigned LocalBaseSubmoduleID = Record[1]; if (F.LocalNumSubmodules > 0) { // Introduce the global -> local mapping for submodules within this // module. GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F)); // Introduce the local -> global mapping for submodules within this // module. F.SubmoduleRemap.insertOrReplace( std::make_pair(LocalBaseSubmoduleID, F.BaseSubmoduleID - LocalBaseSubmoduleID)); SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules); } ModuleKind = (Module::ModuleKind)Record[2]; break; } case SUBMODULE_IMPORTS: { for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; Unresolved.Kind = UnresolvedModuleRef::Import; Unresolved.IsWildcard = false; UnresolvedModuleRefs.push_back(Unresolved); } break; } case SUBMODULE_EXPORTS: { for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; Unresolved.Kind = UnresolvedModuleRef::Export; Unresolved.IsWildcard = Record[Idx + 1]; UnresolvedModuleRefs.push_back(Unresolved); } // Once we've loaded the set of exports, there's no reason to keep // the parsed, unresolved exports around. CurrentModule->UnresolvedExports.clear(); break; } case SUBMODULE_REQUIRES: { CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(), Context.getTargetInfo()); break; } case SUBMODULE_LINK_LIBRARY: CurrentModule->LinkLibraries.push_back( Module::LinkLibrary(Blob, Record[0])); break; case SUBMODULE_CONFIG_MACRO: CurrentModule->ConfigMacros.push_back(Blob.str()); break; case SUBMODULE_CONFLICT: { UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[0]; Unresolved.Kind = UnresolvedModuleRef::Conflict; Unresolved.IsWildcard = false; Unresolved.String = Blob; UnresolvedModuleRefs.push_back(Unresolved); break; } case SUBMODULE_INITIALIZERS: SmallVector Inits; for (auto &ID : Record) Inits.push_back(getGlobalDeclID(F, ID)); Context.addLazyModuleInitializers(CurrentModule, Inits); break; } } } /// \brief Parse the record that corresponds to a LangOptions data /// structure. /// /// This routine parses the language options from the AST file and then gives /// them to the AST listener if one is set. /// /// \returns true if the listener deems the file unacceptable, false otherwise. bool ASTReader::ParseLanguageOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, bool AllowCompatibleDifferences) { LangOptions LangOpts; unsigned Idx = 0; #define LANGOPT(Name, Bits, Default, Description) \ LangOpts.Name = Record[Idx++]; #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ LangOpts.set##Name(static_cast(Record[Idx++])); #include "clang/Basic/LangOptions.def" #define SANITIZER(NAME, ID) \ LangOpts.Sanitize.set(SanitizerKind::ID, Record[Idx++]); #include "clang/Basic/Sanitizers.def" for (unsigned N = Record[Idx++]; N; --N) LangOpts.ModuleFeatures.push_back(ReadString(Record, Idx)); ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion); LangOpts.CurrentModule = ReadString(Record, Idx); // Comment options. for (unsigned N = Record[Idx++]; N; --N) { LangOpts.CommentOpts.BlockCommandNames.push_back( ReadString(Record, Idx)); } LangOpts.CommentOpts.ParseAllComments = Record[Idx++]; // OpenMP offloading options. for (unsigned N = Record[Idx++]; N; --N) { LangOpts.OMPTargetTriples.push_back(llvm::Triple(ReadString(Record, Idx))); } LangOpts.OMPHostIRFile = ReadString(Record, Idx); return Listener.ReadLanguageOptions(LangOpts, Complain, AllowCompatibleDifferences); } bool ASTReader::ParseTargetOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, bool AllowCompatibleDifferences) { unsigned Idx = 0; TargetOptions TargetOpts; TargetOpts.Triple = ReadString(Record, Idx); TargetOpts.CPU = ReadString(Record, Idx); TargetOpts.ABI = ReadString(Record, Idx); for (unsigned N = Record[Idx++]; N; --N) { TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx)); } for (unsigned N = Record[Idx++]; N; --N) { TargetOpts.Features.push_back(ReadString(Record, Idx)); } return Listener.ReadTargetOptions(TargetOpts, Complain, AllowCompatibleDifferences); } bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener) { IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions); unsigned Idx = 0; #define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++]; #define ENUM_DIAGOPT(Name, Type, Bits, Default) \ DiagOpts->set##Name(static_cast(Record[Idx++])); #include "clang/Basic/DiagnosticOptions.def" for (unsigned N = Record[Idx++]; N; --N) DiagOpts->Warnings.push_back(ReadString(Record, Idx)); for (unsigned N = Record[Idx++]; N; --N) DiagOpts->Remarks.push_back(ReadString(Record, Idx)); return Listener.ReadDiagnosticOptions(DiagOpts, Complain); } bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener) { FileSystemOptions FSOpts; unsigned Idx = 0; FSOpts.WorkingDir = ReadString(Record, Idx); return Listener.ReadFileSystemOptions(FSOpts, Complain); } bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener) { HeaderSearchOptions HSOpts; unsigned Idx = 0; HSOpts.Sysroot = ReadString(Record, Idx); // Include entries. for (unsigned N = Record[Idx++]; N; --N) { std::string Path = ReadString(Record, Idx); frontend::IncludeDirGroup Group = static_cast(Record[Idx++]); bool IsFramework = Record[Idx++]; bool IgnoreSysRoot = Record[Idx++]; HSOpts.UserEntries.emplace_back(std::move(Path), Group, IsFramework, IgnoreSysRoot); } // System header prefixes. for (unsigned N = Record[Idx++]; N; --N) { std::string Prefix = ReadString(Record, Idx); bool IsSystemHeader = Record[Idx++]; HSOpts.SystemHeaderPrefixes.emplace_back(std::move(Prefix), IsSystemHeader); } HSOpts.ResourceDir = ReadString(Record, Idx); HSOpts.ModuleCachePath = ReadString(Record, Idx); HSOpts.ModuleUserBuildPath = ReadString(Record, Idx); HSOpts.DisableModuleHash = Record[Idx++]; HSOpts.UseBuiltinIncludes = Record[Idx++]; HSOpts.UseStandardSystemIncludes = Record[Idx++]; HSOpts.UseStandardCXXIncludes = Record[Idx++]; HSOpts.UseLibcxx = Record[Idx++]; std::string SpecificModuleCachePath = ReadString(Record, Idx); return Listener.ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, Complain); } bool ASTReader::ParsePreprocessorOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, std::string &SuggestedPredefines) { PreprocessorOptions PPOpts; unsigned Idx = 0; // Macro definitions/undefs for (unsigned N = Record[Idx++]; N; --N) { std::string Macro = ReadString(Record, Idx); bool IsUndef = Record[Idx++]; PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef)); } // Includes for (unsigned N = Record[Idx++]; N; --N) { PPOpts.Includes.push_back(ReadString(Record, Idx)); } // Macro Includes for (unsigned N = Record[Idx++]; N; --N) { PPOpts.MacroIncludes.push_back(ReadString(Record, Idx)); } PPOpts.UsePredefines = Record[Idx++]; PPOpts.DetailedRecord = Record[Idx++]; PPOpts.ImplicitPCHInclude = ReadString(Record, Idx); PPOpts.ImplicitPTHInclude = ReadString(Record, Idx); PPOpts.ObjCXXARCStandardLibrary = static_cast(Record[Idx++]); SuggestedPredefines.clear(); return Listener.ReadPreprocessorOptions(PPOpts, Complain, SuggestedPredefines); } std::pair ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) { GlobalPreprocessedEntityMapType::iterator I = GlobalPreprocessedEntityMap.find(GlobalIndex); assert(I != GlobalPreprocessedEntityMap.end() && "Corrupted global preprocessed entity map"); ModuleFile *M = I->second; unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID; return std::make_pair(M, LocalIndex); } llvm::iterator_range ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const { if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord()) return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID, Mod.NumPreprocessedEntities); return llvm::make_range(PreprocessingRecord::iterator(), PreprocessingRecord::iterator()); } llvm::iterator_range ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) { return llvm::make_range( ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls), ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls + Mod.NumFileSortedDecls)); } PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { PreprocessedEntityID PPID = Index+1; std::pair PPInfo = getModulePreprocessedEntity(Index); ModuleFile &M = *PPInfo.first; unsigned LocalIndex = PPInfo.second; const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; if (!PP.getPreprocessingRecord()) { Error("no preprocessing record"); return nullptr; } SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset); llvm::BitstreamEntry Entry = M.PreprocessorDetailCursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd); if (Entry.Kind != llvm::BitstreamEntry::Record) return nullptr; // Read the record. SourceRange Range(TranslateSourceLocation(M, PPOffs.getBegin()), TranslateSourceLocation(M, PPOffs.getEnd())); PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); StringRef Blob; RecordData Record; PreprocessorDetailRecordTypes RecType = (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.readRecord( Entry.ID, Record, &Blob); switch (RecType) { case PPD_MACRO_EXPANSION: { bool isBuiltin = Record[0]; IdentifierInfo *Name = nullptr; MacroDefinitionRecord *Def = nullptr; if (isBuiltin) Name = getLocalIdentifier(M, Record[1]); else { PreprocessedEntityID GlobalID = getGlobalPreprocessedEntityID(M, Record[1]); Def = cast( PPRec.getLoadedPreprocessedEntity(GlobalID - 1)); } MacroExpansion *ME; if (isBuiltin) ME = new (PPRec) MacroExpansion(Name, Range); else ME = new (PPRec) MacroExpansion(Def, Range); return ME; } case PPD_MACRO_DEFINITION: { // Decode the identifier info and then check again; if the macro is // still defined and associated with the identifier, IdentifierInfo *II = getLocalIdentifier(M, Record[0]); MacroDefinitionRecord *MD = new (PPRec) MacroDefinitionRecord(II, Range); if (DeserializationListener) DeserializationListener->MacroDefinitionRead(PPID, MD); return MD; } case PPD_INCLUSION_DIRECTIVE: { const char *FullFileNameStart = Blob.data() + Record[0]; StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]); const FileEntry *File = nullptr; if (!FullFileName.empty()) File = PP.getFileManager().getFile(FullFileName); // FIXME: Stable encoding InclusionDirective::InclusionKind Kind = static_cast(Record[2]); InclusionDirective *ID = new (PPRec) InclusionDirective(PPRec, Kind, StringRef(Blob.data(), Record[0]), Record[1], Record[3], File, Range); return ID; } } llvm_unreachable("Invalid PreprocessorDetailRecordTypes"); } /// \brief \arg SLocMapI points at a chunk of a module that contains no /// preprocessed entities or the entities it contains are not the ones we are /// looking for. Find the next module that contains entities and return the ID /// of the first entry. PreprocessedEntityID ASTReader::findNextPreprocessedEntity( GlobalSLocOffsetMapType::const_iterator SLocMapI) const { ++SLocMapI; for (GlobalSLocOffsetMapType::const_iterator EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) { ModuleFile &M = *SLocMapI->second; if (M.NumPreprocessedEntities) return M.BasePreprocessedEntityID; } return getTotalNumPreprocessedEntities(); } namespace { struct PPEntityComp { const ASTReader &Reader; ModuleFile &M; PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { } bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const { SourceLocation LHS = getLoc(L); SourceLocation RHS = getLoc(R); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } bool operator()(const PPEntityOffset &L, SourceLocation RHS) const { SourceLocation LHS = getLoc(L); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } bool operator()(SourceLocation LHS, const PPEntityOffset &R) const { SourceLocation RHS = getLoc(R); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } SourceLocation getLoc(const PPEntityOffset &PPE) const { return Reader.TranslateSourceLocation(M, PPE.getBegin()); } }; } // end anonymous namespace PreprocessedEntityID ASTReader::findPreprocessedEntity(SourceLocation Loc, bool EndsAfter) const { if (SourceMgr.isLocalSourceLocation(Loc)) return getTotalNumPreprocessedEntities(); GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find( SourceManager::MaxLoadedOffset - Loc.getOffset() - 1); assert(SLocMapI != GlobalSLocOffsetMap.end() && "Corrupted global sloc offset map"); if (SLocMapI->second->NumPreprocessedEntities == 0) return findNextPreprocessedEntity(SLocMapI); ModuleFile &M = *SLocMapI->second; typedef const PPEntityOffset *pp_iterator; pp_iterator pp_begin = M.PreprocessedEntityOffsets; pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; size_t Count = M.NumPreprocessedEntities; size_t Half; pp_iterator First = pp_begin; pp_iterator PPI; if (EndsAfter) { PPI = std::upper_bound(pp_begin, pp_end, Loc, PPEntityComp(*this, M)); } else { // Do a binary search manually instead of using std::lower_bound because // The end locations of entities may be unordered (when a macro expansion // is inside another macro argument), but for this case it is not important // whether we get the first macro expansion or its containing macro. while (Count > 0) { Half = Count / 2; PPI = First; std::advance(PPI, Half); if (SourceMgr.isBeforeInTranslationUnit( TranslateSourceLocation(M, PPI->getEnd()), Loc)) { First = PPI; ++First; Count = Count - Half - 1; } else Count = Half; } } if (PPI == pp_end) return findNextPreprocessedEntity(SLocMapI); return M.BasePreprocessedEntityID + (PPI - pp_begin); } /// \brief Returns a pair of [Begin, End) indices of preallocated /// preprocessed entities that \arg Range encompasses. std::pair ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) { if (Range.isInvalid()) return std::make_pair(0,0); assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); PreprocessedEntityID BeginID = findPreprocessedEntity(Range.getBegin(), false); PreprocessedEntityID EndID = findPreprocessedEntity(Range.getEnd(), true); return std::make_pair(BeginID, EndID); } /// \brief Optionally returns true or false if the preallocated preprocessed /// entity with index \arg Index came from file \arg FID. Optional ASTReader::isPreprocessedEntityInFileID(unsigned Index, FileID FID) { if (FID.isInvalid()) return false; std::pair PPInfo = getModulePreprocessedEntity(Index); ModuleFile &M = *PPInfo.first; unsigned LocalIndex = PPInfo.second; const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; SourceLocation Loc = TranslateSourceLocation(M, PPOffs.getBegin()); if (Loc.isInvalid()) return false; if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID)) return true; else return false; } namespace { /// \brief Visitor used to search for information about a header file. class HeaderFileInfoVisitor { const FileEntry *FE; Optional HFI; public: explicit HeaderFileInfoVisitor(const FileEntry *FE) : FE(FE) { } bool operator()(ModuleFile &M) { HeaderFileInfoLookupTable *Table = static_cast(M.HeaderFileInfoTable); if (!Table) return false; // Look in the on-disk hash table for an entry for this file name. HeaderFileInfoLookupTable::iterator Pos = Table->find(FE); if (Pos == Table->end()) return false; HFI = *Pos; return true; } Optional getHeaderFileInfo() const { return HFI; } }; } // end anonymous namespace HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { HeaderFileInfoVisitor Visitor(FE); ModuleMgr.visit(Visitor); if (Optional HFI = Visitor.getHeaderFileInfo()) return *HFI; return HeaderFileInfo(); } void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { using DiagState = DiagnosticsEngine::DiagState; SmallVector DiagStates; for (ModuleFile &F : ModuleMgr) { unsigned Idx = 0; auto &Record = F.PragmaDiagMappings; if (Record.empty()) continue; DiagStates.clear(); auto ReadDiagState = [&](const DiagState &BasedOn, SourceLocation Loc, bool IncludeNonPragmaStates) -> DiagnosticsEngine::DiagState * { unsigned BackrefID = Record[Idx++]; if (BackrefID != 0) return DiagStates[BackrefID - 1]; // A new DiagState was created here. Diag.DiagStates.push_back(BasedOn); DiagState *NewState = &Diag.DiagStates.back(); DiagStates.push_back(NewState); unsigned Size = Record[Idx++]; assert(Idx + Size * 2 <= Record.size() && "Invalid data, not enough diag/map pairs"); while (Size--) { unsigned DiagID = Record[Idx++]; DiagnosticMapping NewMapping = DiagnosticMapping::deserialize(Record[Idx++]); if (!NewMapping.isPragma() && !IncludeNonPragmaStates) continue; DiagnosticMapping &Mapping = NewState->getOrAddMapping(DiagID); // If this mapping was specified as a warning but the severity was // upgraded due to diagnostic settings, simulate the current diagnostic // settings (and use a warning). if (NewMapping.wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) { NewMapping.setSeverity(diag::Severity::Warning); NewMapping.setUpgradedFromWarning(false); } Mapping = NewMapping; } return NewState; }; // Read the first state. DiagState *FirstState; if (F.Kind == MK_ImplicitModule) { // Implicitly-built modules are reused with different diagnostic // settings. Use the initial diagnostic state from Diag to simulate this // compilation's diagnostic settings. FirstState = Diag.DiagStatesByLoc.FirstDiagState; DiagStates.push_back(FirstState); // Skip the initial diagnostic state from the serialized module. assert(Record[1] == 0 && "Invalid data, unexpected backref in initial state"); Idx = 3 + Record[2] * 2; assert(Idx < Record.size() && "Invalid data, not enough state change pairs in initial state"); } else if (F.isModule()) { // For an explicit module, preserve the flags from the module build // command line (-w, -Weverything, -Werror, ...) along with any explicit // -Wblah flags. unsigned Flags = Record[Idx++]; DiagState Initial; Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1; Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1; Initial.WarningsAsErrors = Flags & 1; Flags >>= 1; Initial.EnableAllWarnings = Flags & 1; Flags >>= 1; Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1; Initial.ExtBehavior = (diag::Severity)Flags; FirstState = ReadDiagState(Initial, SourceLocation(), true); // Set up the root buffer of the module to start with the initial // diagnostic state of the module itself, to cover files that contain no // explicit transitions (for which we did not serialize anything). Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID] .StateTransitions.push_back({FirstState, 0}); } else { // For prefix ASTs, start with whatever the user configured on the // command line. Idx++; // Skip flags. FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState, SourceLocation(), false); } // Read the state transitions. unsigned NumLocations = Record[Idx++]; while (NumLocations--) { assert(Idx < Record.size() && "Invalid data, missing pragma diagnostic states"); SourceLocation Loc = ReadSourceLocation(F, Record[Idx++]); auto IDAndOffset = SourceMgr.getDecomposedLoc(Loc); assert(IDAndOffset.second == 0 && "not a start location for a FileID"); unsigned Transitions = Record[Idx++]; // Note that we don't need to set up Parent/ParentOffset here, because // we won't be changing the diagnostic state within imported FileIDs // (other than perhaps appending to the main source file, which has no // parent). auto &F = Diag.DiagStatesByLoc.Files[IDAndOffset.first]; F.StateTransitions.reserve(F.StateTransitions.size() + Transitions); for (unsigned I = 0; I != Transitions; ++I) { unsigned Offset = Record[Idx++]; auto *State = ReadDiagState(*FirstState, Loc.getLocWithOffset(Offset), false); F.StateTransitions.push_back({State, Offset}); } } // Read the final state. assert(Idx < Record.size() && "Invalid data, missing final pragma diagnostic state"); SourceLocation CurStateLoc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); auto *CurState = ReadDiagState(*FirstState, CurStateLoc, false); if (!F.isModule()) { Diag.DiagStatesByLoc.CurDiagState = CurState; Diag.DiagStatesByLoc.CurDiagStateLoc = CurStateLoc; // Preserve the property that the imaginary root file describes the // current state. auto &T = Diag.DiagStatesByLoc.Files[FileID()].StateTransitions; if (T.empty()) T.push_back({CurState, 0}); else T[0].State = CurState; } // Don't try to read these mappings again. Record.clear(); } } /// \brief Get the correct cursor and offset for loading a type. ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index); assert(I != GlobalTypeMap.end() && "Corrupted global type map"); ModuleFile *M = I->second; return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]); } /// \brief Read and return the type with the given index.. /// /// The index is the type ID, shifted and minus the number of predefs. This /// routine actually reads the record corresponding to the type at the given /// location. It is a helper routine for GetType, which deals with reading type /// IDs. QualType ASTReader::readTypeRecord(unsigned Index) { RecordLocation Loc = TypeCursorForIndex(Index); BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; // Keep track of where we are in the stream, then jump back there // after reading this type. SavedStreamPosition SavedPosition(DeclsCursor); ReadingKindTracker ReadingKind(Read_Type, *this); // Note that we are loading a type record. Deserializing AType(this); unsigned Idx = 0; DeclsCursor.JumpToBit(Loc.Offset); RecordData Record; unsigned Code = DeclsCursor.ReadCode(); switch ((TypeCode)DeclsCursor.readRecord(Code, Record)) { case TYPE_EXT_QUAL: { if (Record.size() != 2) { Error("Incorrect encoding of extended qualifier type"); return QualType(); } QualType Base = readType(*Loc.F, Record, Idx); Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]); return Context.getQualifiedType(Base, Quals); } case TYPE_COMPLEX: { if (Record.size() != 1) { Error("Incorrect encoding of complex type"); return QualType(); } QualType ElemType = readType(*Loc.F, Record, Idx); return Context.getComplexType(ElemType); } case TYPE_POINTER: { if (Record.size() != 1) { Error("Incorrect encoding of pointer type"); return QualType(); } QualType PointeeType = readType(*Loc.F, Record, Idx); return Context.getPointerType(PointeeType); } case TYPE_DECAYED: { if (Record.size() != 1) { Error("Incorrect encoding of decayed type"); return QualType(); } QualType OriginalType = readType(*Loc.F, Record, Idx); QualType DT = Context.getAdjustedParameterType(OriginalType); if (!isa(DT)) Error("Decayed type does not decay"); return DT; } case TYPE_ADJUSTED: { if (Record.size() != 2) { Error("Incorrect encoding of adjusted type"); return QualType(); } QualType OriginalTy = readType(*Loc.F, Record, Idx); QualType AdjustedTy = readType(*Loc.F, Record, Idx); return Context.getAdjustedType(OriginalTy, AdjustedTy); } case TYPE_BLOCK_POINTER: { if (Record.size() != 1) { Error("Incorrect encoding of block pointer type"); return QualType(); } QualType PointeeType = readType(*Loc.F, Record, Idx); return Context.getBlockPointerType(PointeeType); } case TYPE_LVALUE_REFERENCE: { if (Record.size() != 2) { Error("Incorrect encoding of lvalue reference type"); return QualType(); } QualType PointeeType = readType(*Loc.F, Record, Idx); return Context.getLValueReferenceType(PointeeType, Record[1]); } case TYPE_RVALUE_REFERENCE: { if (Record.size() != 1) { Error("Incorrect encoding of rvalue reference type"); return QualType(); } QualType PointeeType = readType(*Loc.F, Record, Idx); return Context.getRValueReferenceType(PointeeType); } case TYPE_MEMBER_POINTER: { if (Record.size() != 2) { Error("Incorrect encoding of member pointer type"); return QualType(); } QualType PointeeType = readType(*Loc.F, Record, Idx); QualType ClassType = readType(*Loc.F, Record, Idx); if (PointeeType.isNull() || ClassType.isNull()) return QualType(); return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr()); } case TYPE_CONSTANT_ARRAY: { QualType ElementType = readType(*Loc.F, Record, Idx); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; unsigned IndexTypeQuals = Record[2]; unsigned Idx = 3; llvm::APInt Size = ReadAPInt(Record, Idx); return Context.getConstantArrayType(ElementType, Size, ASM, IndexTypeQuals); } case TYPE_INCOMPLETE_ARRAY: { QualType ElementType = readType(*Loc.F, Record, Idx); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; unsigned IndexTypeQuals = Record[2]; return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals); } case TYPE_VARIABLE_ARRAY: { QualType ElementType = readType(*Loc.F, Record, Idx); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; unsigned IndexTypeQuals = Record[2]; SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]); SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]); return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F), ASM, IndexTypeQuals, SourceRange(LBLoc, RBLoc)); } case TYPE_VECTOR: { if (Record.size() != 3) { Error("incorrect encoding of vector type in AST file"); return QualType(); } QualType ElementType = readType(*Loc.F, Record, Idx); unsigned NumElements = Record[1]; unsigned VecKind = Record[2]; return Context.getVectorType(ElementType, NumElements, (VectorType::VectorKind)VecKind); } case TYPE_EXT_VECTOR: { if (Record.size() != 3) { Error("incorrect encoding of extended vector type in AST file"); return QualType(); } QualType ElementType = readType(*Loc.F, Record, Idx); unsigned NumElements = Record[1]; return Context.getExtVectorType(ElementType, NumElements); } case TYPE_FUNCTION_NO_PROTO: { if (Record.size() != 7) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = readType(*Loc.F, Record, Idx); FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], (CallingConv)Record[4], Record[5], Record[6]); return Context.getFunctionNoProtoType(ResultType, Info); } case TYPE_FUNCTION_PROTO: { QualType ResultType = readType(*Loc.F, Record, Idx); FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1], /*hasregparm*/ Record[2], /*regparm*/ Record[3], static_cast(Record[4]), /*produces*/ Record[5], /*nocallersavedregs*/ Record[6]); unsigned Idx = 7; EPI.Variadic = Record[Idx++]; EPI.HasTrailingReturn = Record[Idx++]; EPI.TypeQuals = Record[Idx++]; EPI.RefQualifier = static_cast(Record[Idx++]); SmallVector ExceptionStorage; readExceptionSpec(*Loc.F, ExceptionStorage, EPI.ExceptionSpec, Record, Idx); unsigned NumParams = Record[Idx++]; SmallVector ParamTypes; for (unsigned I = 0; I != NumParams; ++I) ParamTypes.push_back(readType(*Loc.F, Record, Idx)); SmallVector ExtParameterInfos; if (Idx != Record.size()) { for (unsigned I = 0; I != NumParams; ++I) ExtParameterInfos.push_back( FunctionProtoType::ExtParameterInfo ::getFromOpaqueValue(Record[Idx++])); EPI.ExtParameterInfos = ExtParameterInfos.data(); } assert(Idx == Record.size()); return Context.getFunctionType(ResultType, ParamTypes, EPI); } case TYPE_UNRESOLVED_USING: { unsigned Idx = 0; return Context.getTypeDeclType( ReadDeclAs(*Loc.F, Record, Idx)); } case TYPE_TYPEDEF: { if (Record.size() != 2) { Error("incorrect encoding of typedef type"); return QualType(); } unsigned Idx = 0; TypedefNameDecl *Decl = ReadDeclAs(*Loc.F, Record, Idx); QualType Canonical = readType(*Loc.F, Record, Idx); if (!Canonical.isNull()) Canonical = Context.getCanonicalType(Canonical); return Context.getTypedefType(Decl, Canonical); } case TYPE_TYPEOF_EXPR: return Context.getTypeOfExprType(ReadExpr(*Loc.F)); case TYPE_TYPEOF: { if (Record.size() != 1) { Error("incorrect encoding of typeof(type) in AST file"); return QualType(); } QualType UnderlyingType = readType(*Loc.F, Record, Idx); return Context.getTypeOfType(UnderlyingType); } case TYPE_DECLTYPE: { QualType UnderlyingType = readType(*Loc.F, Record, Idx); return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType); } case TYPE_UNARY_TRANSFORM: { QualType BaseType = readType(*Loc.F, Record, Idx); QualType UnderlyingType = readType(*Loc.F, Record, Idx); UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2]; return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind); } case TYPE_AUTO: { QualType Deduced = readType(*Loc.F, Record, Idx); AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++]; bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; return Context.getAutoType(Deduced, Keyword, IsDependent); } case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: { TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); QualType Deduced = readType(*Loc.F, Record, Idx); bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; return Context.getDeducedTemplateSpecializationType(Name, Deduced, IsDependent); } case TYPE_RECORD: { if (Record.size() != 2) { Error("incorrect encoding of record type"); return QualType(); } unsigned Idx = 0; bool IsDependent = Record[Idx++]; RecordDecl *RD = ReadDeclAs(*Loc.F, Record, Idx); RD = cast_or_null(RD->getCanonicalDecl()); QualType T = Context.getRecordType(RD); const_cast(T.getTypePtr())->setDependent(IsDependent); return T; } case TYPE_ENUM: { if (Record.size() != 2) { Error("incorrect encoding of enum type"); return QualType(); } unsigned Idx = 0; bool IsDependent = Record[Idx++]; QualType T = Context.getEnumType(ReadDeclAs(*Loc.F, Record, Idx)); const_cast(T.getTypePtr())->setDependent(IsDependent); return T; } case TYPE_ATTRIBUTED: { if (Record.size() != 3) { Error("incorrect encoding of attributed type"); return QualType(); } QualType modifiedType = readType(*Loc.F, Record, Idx); QualType equivalentType = readType(*Loc.F, Record, Idx); AttributedType::Kind kind = static_cast(Record[2]); return Context.getAttributedType(kind, modifiedType, equivalentType); } case TYPE_PAREN: { if (Record.size() != 1) { Error("incorrect encoding of paren type"); return QualType(); } QualType InnerType = readType(*Loc.F, Record, Idx); return Context.getParenType(InnerType); } case TYPE_PACK_EXPANSION: { if (Record.size() != 2) { Error("incorrect encoding of pack expansion type"); return QualType(); } QualType Pattern = readType(*Loc.F, Record, Idx); if (Pattern.isNull()) return QualType(); Optional NumExpansions; if (Record[1]) NumExpansions = Record[1] - 1; return Context.getPackExpansionType(Pattern, NumExpansions); } case TYPE_ELABORATED: { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); QualType NamedType = readType(*Loc.F, Record, Idx); return Context.getElaboratedType(Keyword, NNS, NamedType); } case TYPE_OBJC_INTERFACE: { unsigned Idx = 0; ObjCInterfaceDecl *ItfD = ReadDeclAs(*Loc.F, Record, Idx); return Context.getObjCInterfaceType(ItfD->getCanonicalDecl()); } case TYPE_OBJC_TYPE_PARAM: { unsigned Idx = 0; ObjCTypeParamDecl *Decl = ReadDeclAs(*Loc.F, Record, Idx); unsigned NumProtos = Record[Idx++]; SmallVector Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(ReadDeclAs(*Loc.F, Record, Idx)); return Context.getObjCTypeParamType(Decl, Protos); } case TYPE_OBJC_OBJECT: { unsigned Idx = 0; QualType Base = readType(*Loc.F, Record, Idx); unsigned NumTypeArgs = Record[Idx++]; SmallVector TypeArgs; for (unsigned I = 0; I != NumTypeArgs; ++I) TypeArgs.push_back(readType(*Loc.F, Record, Idx)); unsigned NumProtos = Record[Idx++]; SmallVector Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(ReadDeclAs(*Loc.F, Record, Idx)); bool IsKindOf = Record[Idx++]; return Context.getObjCObjectType(Base, TypeArgs, Protos, IsKindOf); } case TYPE_OBJC_OBJECT_POINTER: { unsigned Idx = 0; QualType Pointee = readType(*Loc.F, Record, Idx); return Context.getObjCObjectPointerType(Pointee); } case TYPE_SUBST_TEMPLATE_TYPE_PARM: { unsigned Idx = 0; QualType Parm = readType(*Loc.F, Record, Idx); QualType Replacement = readType(*Loc.F, Record, Idx); return Context.getSubstTemplateTypeParmType( cast(Parm), Context.getCanonicalType(Replacement)); } case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: { unsigned Idx = 0; QualType Parm = readType(*Loc.F, Record, Idx); TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx); return Context.getSubstTemplateTypeParmPackType( cast(Parm), ArgPack); } case TYPE_INJECTED_CLASS_NAME: { CXXRecordDecl *D = ReadDeclAs(*Loc.F, Record, Idx); QualType TST = readType(*Loc.F, Record, Idx); // probably derivable // FIXME: ASTContext::getInjectedClassNameType is not currently suitable // for AST reading, too much interdependencies. const Type *T = nullptr; for (auto *DI = D; DI; DI = DI->getPreviousDecl()) { if (const Type *Existing = DI->getTypeForDecl()) { T = Existing; break; } } if (!T) { T = new (Context, TypeAlignment) InjectedClassNameType(D, TST); for (auto *DI = D; DI; DI = DI->getPreviousDecl()) DI->setTypeForDecl(T); } return QualType(T, 0); } case TYPE_TEMPLATE_TYPE_PARM: { unsigned Idx = 0; unsigned Depth = Record[Idx++]; unsigned Index = Record[Idx++]; bool Pack = Record[Idx++]; TemplateTypeParmDecl *D = ReadDeclAs(*Loc.F, Record, Idx); return Context.getTemplateTypeParmType(Depth, Index, Pack, D); } case TYPE_DEPENDENT_NAME: { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx); QualType Canon = readType(*Loc.F, Record, Idx); if (!Canon.isNull()) Canon = Context.getCanonicalType(Canon); return Context.getDependentNameType(Keyword, NNS, Name, Canon); } case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx); unsigned NumArgs = Record[Idx++]; SmallVector Args; Args.reserve(NumArgs); while (NumArgs--) Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx)); return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name, Args); } case TYPE_DEPENDENT_SIZED_ARRAY: { unsigned Idx = 0; // ArrayType QualType ElementType = readType(*Loc.F, Record, Idx); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[Idx++]; unsigned IndexTypeQuals = Record[Idx++]; // DependentSizedArrayType Expr *NumElts = ReadExpr(*Loc.F); SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx); return Context.getDependentSizedArrayType(ElementType, NumElts, ASM, IndexTypeQuals, Brackets); } case TYPE_TEMPLATE_SPECIALIZATION: { unsigned Idx = 0; bool IsDependent = Record[Idx++]; TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); SmallVector Args; ReadTemplateArgumentList(Args, *Loc.F, Record, Idx); QualType Underlying = readType(*Loc.F, Record, Idx); QualType T; if (Underlying.isNull()) T = Context.getCanonicalTemplateSpecializationType(Name, Args); else T = Context.getTemplateSpecializationType(Name, Args, Underlying); const_cast(T.getTypePtr())->setDependent(IsDependent); return T; } case TYPE_ATOMIC: { if (Record.size() != 1) { Error("Incorrect encoding of atomic type"); return QualType(); } QualType ValueType = readType(*Loc.F, Record, Idx); return Context.getAtomicType(ValueType); } case TYPE_PIPE: { if (Record.size() != 2) { Error("Incorrect encoding of pipe type"); return QualType(); } // Reading the pipe element type. QualType ElementType = readType(*Loc.F, Record, Idx); unsigned ReadOnly = Record[1]; return Context.getPipeType(ElementType, ReadOnly); } case TYPE_DEPENDENT_SIZED_EXT_VECTOR: { unsigned Idx = 0; // DependentSizedExtVectorType QualType ElementType = readType(*Loc.F, Record, Idx); Expr *SizeExpr = ReadExpr(*Loc.F); SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); return Context.getDependentSizedExtVectorType(ElementType, SizeExpr, AttrLoc); } } llvm_unreachable("Invalid TypeCode!"); } void ASTReader::readExceptionSpec(ModuleFile &ModuleFile, SmallVectorImpl &Exceptions, FunctionProtoType::ExceptionSpecInfo &ESI, const RecordData &Record, unsigned &Idx) { ExceptionSpecificationType EST = static_cast(Record[Idx++]); ESI.Type = EST; if (EST == EST_Dynamic) { for (unsigned I = 0, N = Record[Idx++]; I != N; ++I) Exceptions.push_back(readType(ModuleFile, Record, Idx)); ESI.Exceptions = Exceptions; } else if (EST == EST_ComputedNoexcept) { ESI.NoexceptExpr = ReadExpr(ModuleFile); } else if (EST == EST_Uninstantiated) { ESI.SourceDecl = ReadDeclAs(ModuleFile, Record, Idx); ESI.SourceTemplate = ReadDeclAs(ModuleFile, Record, Idx); } else if (EST == EST_Unevaluated) { ESI.SourceDecl = ReadDeclAs(ModuleFile, Record, Idx); } } class clang::TypeLocReader : public TypeLocVisitor { ModuleFile *F; ASTReader *Reader; const ASTReader::RecordData &Record; unsigned &Idx; SourceLocation ReadSourceLocation() { return Reader->ReadSourceLocation(*F, Record, Idx); } TypeSourceInfo *GetTypeSourceInfo() { return Reader->GetTypeSourceInfo(*F, Record, Idx); } NestedNameSpecifierLoc ReadNestedNameSpecifierLoc() { return Reader->ReadNestedNameSpecifierLoc(*F, Record, Idx); } public: TypeLocReader(ModuleFile &F, ASTReader &Reader, const ASTReader::RecordData &Record, unsigned &Idx) : F(&F), Reader(&Reader), Record(Record), Idx(Idx) {} // We want compile-time assurance that we've enumerated all of // these, so unfortunately we have to declare them first, then // define them out-of-line. #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); #include "clang/AST/TypeLocNodes.def" void VisitFunctionTypeLoc(FunctionTypeLoc); void VisitArrayTypeLoc(ArrayTypeLoc); }; void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { TL.setBuiltinLoc(ReadSourceLocation()); if (TL.needsExtraLocalData()) { TL.setWrittenTypeSpec(static_cast(Record[Idx++])); TL.setWrittenSignSpec(static_cast(Record[Idx++])); TL.setWrittenWidthSpec(static_cast(Record[Idx++])); TL.setModeAttr(Record[Idx++]); } } void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation()); } void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) { // nothing to do } void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing to do } void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { TL.setCaretLoc(ReadSourceLocation()); } void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { TL.setAmpLoc(ReadSourceLocation()); } void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { TL.setAmpAmpLoc(ReadSourceLocation()); } void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation()); TL.setClassTInfo(GetTypeSourceInfo()); } void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { TL.setLBracketLoc(ReadSourceLocation()); TL.setRBracketLoc(ReadSourceLocation()); if (Record[Idx++]) TL.setSizeExpr(Reader->ReadExpr(*F)); else TL.setSizeExpr(nullptr); } void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocReader::VisitDependentSizedArrayTypeLoc( DependentSizedArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { TL.setLocalRangeBegin(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); TL.setExceptionSpecRange(SourceRange(Reader->ReadSourceLocation(*F, Record, Idx), Reader->ReadSourceLocation(*F, Record, Idx))); TL.setLocalRangeEnd(ReadSourceLocation()); for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) { TL.setParam(i, Reader->ReadDeclAs(*F, Record, Idx)); } } void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { TL.setTypeofLoc(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); } void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { TL.setTypeofLoc(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); TL.setUnderlyingTInfo(GetTypeSourceInfo()); } void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { TL.setKWLoc(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); TL.setUnderlyingTInfo(GetTypeSourceInfo()); } void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( DeducedTemplateSpecializationTypeLoc TL) { TL.setTemplateNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { TL.setAttrNameLoc(ReadSourceLocation()); if (TL.hasAttrOperand()) { SourceRange range; range.setBegin(ReadSourceLocation()); range.setEnd(ReadSourceLocation()); TL.setAttrOperandParensRange(range); } if (TL.hasAttrExprOperand()) { if (Record[Idx++]) TL.setAttrExprOperand(Reader->ReadExpr(*F)); else TL.setAttrExprOperand(nullptr); } else if (TL.hasAttrEnumOperand()) TL.setAttrEnumOperandLoc(ReadSourceLocation()); } void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( SubstTemplateTypeParmPackTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { TL.setTemplateKeywordLoc(ReadSourceLocation()); TL.setTemplateNameLoc(ReadSourceLocation()); TL.setLAngleLoc(ReadSourceLocation()); TL.setRAngleLoc(ReadSourceLocation()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) TL.setArgLocInfo( i, Reader->GetTemplateArgumentLocInfo( *F, TL.getTypePtr()->getArg(i).getKind(), Record, Idx)); } void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); } void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { TL.setElaboratedKeywordLoc(ReadSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); } void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { TL.setElaboratedKeywordLoc(ReadSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { TL.setElaboratedKeywordLoc(ReadSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); TL.setTemplateKeywordLoc(ReadSourceLocation()); TL.setTemplateNameLoc(ReadSourceLocation()); TL.setLAngleLoc(ReadSourceLocation()); TL.setRAngleLoc(ReadSourceLocation()); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) TL.setArgLocInfo( I, Reader->GetTemplateArgumentLocInfo( *F, TL.getTypePtr()->getArg(I).getKind(), Record, Idx)); } void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { TL.setEllipsisLoc(ReadSourceLocation()); } void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } void TypeLocReader::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { if (TL.getNumProtocols()) { TL.setProtocolLAngleLoc(ReadSourceLocation()); TL.setProtocolRAngleLoc(ReadSourceLocation()); } for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, ReadSourceLocation()); } void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { TL.setHasBaseTypeAsWritten(Record[Idx++]); TL.setTypeArgsLAngleLoc(ReadSourceLocation()); TL.setTypeArgsRAngleLoc(ReadSourceLocation()); for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) TL.setTypeArgTInfo(i, GetTypeSourceInfo()); TL.setProtocolLAngleLoc(ReadSourceLocation()); TL.setProtocolRAngleLoc(ReadSourceLocation()); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, ReadSourceLocation()); } void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation()); } void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { TL.setKWLoc(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); } void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) { TL.setKWLoc(ReadSourceLocation()); } TypeSourceInfo * ASTReader::GetTypeSourceInfo(ModuleFile &F, const ASTReader::RecordData &Record, unsigned &Idx) { QualType InfoTy = readType(F, Record, Idx); if (InfoTy.isNull()) return nullptr; TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy); TypeLocReader TLR(F, *this, Record, Idx); for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) TLR.Visit(TL); return TInfo; } QualType ASTReader::GetType(TypeID ID) { unsigned FastQuals = ID & Qualifiers::FastMask; unsigned Index = ID >> Qualifiers::FastWidth; if (Index < NUM_PREDEF_TYPE_IDS) { QualType T; switch ((PredefinedTypeIDs)Index) { case PREDEF_TYPE_NULL_ID: return QualType(); case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break; case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break; case PREDEF_TYPE_CHAR_U_ID: case PREDEF_TYPE_CHAR_S_ID: // FIXME: Check that the signedness of CharTy is correct! T = Context.CharTy; break; case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break; case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break; case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break; case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break; case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break; case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break; case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break; case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break; case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break; case PREDEF_TYPE_INT_ID: T = Context.IntTy; break; case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break; case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break; case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break; case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break; case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break; case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break; case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; case PREDEF_TYPE_FLOAT128_ID: T = Context.Float128Ty; break; case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break; case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break; case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break; case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break; case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break; case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break; case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break; case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break; case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break; case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break; #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ break; #include "clang/Basic/OpenCLImageTypes.def" case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break; case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break; case PREDEF_TYPE_CLK_EVENT_ID: T = Context.OCLClkEventTy; break; case PREDEF_TYPE_QUEUE_ID: T = Context.OCLQueueTy; break; case PREDEF_TYPE_RESERVE_ID_ID: T = Context.OCLReserveIDTy; break; case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; case PREDEF_TYPE_AUTO_RREF_DEDUCT: T = Context.getAutoRRefDeductType(); break; case PREDEF_TYPE_ARC_UNBRIDGED_CAST: T = Context.ARCUnbridgedCastTy; break; case PREDEF_TYPE_BUILTIN_FN: T = Context.BuiltinFnTy; break; case PREDEF_TYPE_OMP_ARRAY_SECTION: T = Context.OMPArraySectionTy; break; } assert(!T.isNull() && "Unknown predefined type"); return T.withFastQualifiers(FastQuals); } Index -= NUM_PREDEF_TYPE_IDS; assert(Index < TypesLoaded.size() && "Type index out-of-range"); if (TypesLoaded[Index].isNull()) { TypesLoaded[Index] = readTypeRecord(Index); if (TypesLoaded[Index].isNull()) return QualType(); TypesLoaded[Index]->setFromAST(); if (DeserializationListener) DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID), TypesLoaded[Index]); } return TypesLoaded[Index].withFastQualifiers(FastQuals); } QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) { return GetType(getGlobalTypeID(F, LocalID)); } serialization::TypeID ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const { unsigned FastQuals = LocalID & Qualifiers::FastMask; unsigned LocalIndex = LocalID >> Qualifiers::FastWidth; if (LocalIndex < NUM_PREDEF_TYPE_IDS) return LocalID; if (!F.ModuleOffsetMap.empty()) ReadModuleOffsetMap(F); ContinuousRangeMap::iterator I = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS); assert(I != F.TypeRemap.end() && "Invalid index into type index remap"); unsigned GlobalIndex = LocalIndex + I->second; return (GlobalIndex << Qualifiers::FastWidth) | FastQuals; } TemplateArgumentLocInfo ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F, TemplateArgument::ArgKind Kind, const RecordData &Record, unsigned &Index) { switch (Kind) { case TemplateArgument::Expression: return ReadExpr(F); case TemplateArgument::Type: return GetTypeSourceInfo(F, Record, Index); case TemplateArgument::Template: { NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Index); SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, SourceLocation()); } case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Index); SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index); return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc); } case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: case TemplateArgument::NullPtr: case TemplateArgument::Pack: // FIXME: Is this right? return TemplateArgumentLocInfo(); } llvm_unreachable("unexpected template argument loc"); } TemplateArgumentLoc ASTReader::ReadTemplateArgumentLoc(ModuleFile &F, const RecordData &Record, unsigned &Index) { TemplateArgument Arg = ReadTemplateArgument(F, Record, Index); if (Arg.getKind() == TemplateArgument::Expression) { if (Record[Index++]) // bool InfoHasSameExpr. return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr())); } return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(), Record, Index)); } const ASTTemplateArgumentListInfo* ASTReader::ReadASTTemplateArgumentListInfo(ModuleFile &F, const RecordData &Record, unsigned &Index) { SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Index); SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Index); unsigned NumArgsAsWritten = Record[Index++]; TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc); for (unsigned i = 0; i != NumArgsAsWritten; ++i) TemplArgsInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Index)); return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo); } Decl *ASTReader::GetExternalDecl(uint32_t ID) { return GetDecl(ID); } void ASTReader::CompleteRedeclChain(const Decl *D) { if (NumCurrentElementsDeserializing) { // We arrange to not care about the complete redeclaration chain while we're // deserializing. Just remember that the AST has marked this one as complete // but that it's not actually complete yet, so we know we still need to // complete it later. PendingIncompleteDeclChains.push_back(const_cast(D)); return; } const DeclContext *DC = D->getDeclContext()->getRedeclContext(); // If this is a named declaration, complete it by looking it up // within its context. // // FIXME: Merging a function definition should merge // all mergeable entities within it. if (isa(DC) || isa(DC) || isa(DC) || isa(DC)) { if (DeclarationName Name = cast(D)->getDeclName()) { if (!getContext().getLangOpts().CPlusPlus && isa(DC)) { // Outside of C++, we don't have a lookup table for the TU, so update // the identifier instead. (For C++ modules, we don't store decls // in the serialized identifier table, so we do the lookup in the TU.) auto *II = Name.getAsIdentifierInfo(); assert(II && "non-identifier name in C?"); if (II->isOutOfDate()) updateOutOfDateIdentifier(*II); } else DC->lookup(Name); } else if (needsAnonymousDeclarationNumber(cast(D))) { // Find all declarations of this kind from the relevant context. for (auto *DCDecl : cast(D->getLexicalDeclContext())->redecls()) { auto *DC = cast(DCDecl); SmallVector Decls; FindExternalLexicalDecls( DC, [&](Decl::Kind K) { return K == D->getKind(); }, Decls); } } } if (auto *CTSD = dyn_cast(D)) CTSD->getSpecializedTemplate()->LoadLazySpecializations(); if (auto *VTSD = dyn_cast(D)) VTSD->getSpecializedTemplate()->LoadLazySpecializations(); if (auto *FD = dyn_cast(D)) { if (auto *Template = FD->getPrimaryTemplate()) Template->LoadLazySpecializations(); } } CXXCtorInitializer ** ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) { RecordLocation Loc = getLocalBitOffset(Offset); BitstreamCursor &Cursor = Loc.F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(Loc.Offset); ReadingKindTracker ReadingKind(Read_Decl, *this); RecordData Record; unsigned Code = Cursor.ReadCode(); unsigned RecCode = Cursor.readRecord(Code, Record); if (RecCode != DECL_CXX_CTOR_INITIALIZERS) { Error("malformed AST file: missing C++ ctor initializers"); return nullptr; } unsigned Idx = 0; return ReadCXXCtorInitializers(*Loc.F, Record, Idx); } CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { RecordLocation Loc = getLocalBitOffset(Offset); BitstreamCursor &Cursor = Loc.F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(Loc.Offset); ReadingKindTracker ReadingKind(Read_Decl, *this); RecordData Record; unsigned Code = Cursor.ReadCode(); unsigned RecCode = Cursor.readRecord(Code, Record); if (RecCode != DECL_CXX_BASE_SPECIFIERS) { Error("malformed AST file: missing C++ base specifiers"); return nullptr; } unsigned Idx = 0; unsigned NumBases = Record[Idx++]; void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases); CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases]; for (unsigned I = 0; I != NumBases; ++I) Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx); return Bases; } serialization::DeclID ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const { if (LocalID < NUM_PREDEF_DECL_IDS) return LocalID; if (!F.ModuleOffsetMap.empty()) ReadModuleOffsetMap(F); ContinuousRangeMap::iterator I = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS); assert(I != F.DeclRemap.end() && "Invalid index into decl index remap"); return LocalID + I->second; } bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, ModuleFile &M) const { // Predefined decls aren't from any module. if (ID < NUM_PREDEF_DECL_IDS) return false; return ID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID && ID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls; } ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) { if (!D->isFromASTFile()) return nullptr; GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID()); assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); return I->second; } SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) { if (ID < NUM_PREDEF_DECL_IDS) return SourceLocation(); unsigned Index = ID - NUM_PREDEF_DECL_IDS; if (Index > DeclsLoaded.size()) { Error("declaration ID out-of-range for AST file"); return SourceLocation(); } if (Decl *D = DeclsLoaded[Index]) return D->getLocation(); SourceLocation Loc; DeclCursorForID(ID, Loc); return Loc; } static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) { switch (ID) { case PREDEF_DECL_NULL_ID: return nullptr; case PREDEF_DECL_TRANSLATION_UNIT_ID: return Context.getTranslationUnitDecl(); case PREDEF_DECL_OBJC_ID_ID: return Context.getObjCIdDecl(); case PREDEF_DECL_OBJC_SEL_ID: return Context.getObjCSelDecl(); case PREDEF_DECL_OBJC_CLASS_ID: return Context.getObjCClassDecl(); case PREDEF_DECL_OBJC_PROTOCOL_ID: return Context.getObjCProtocolDecl(); case PREDEF_DECL_INT_128_ID: return Context.getInt128Decl(); case PREDEF_DECL_UNSIGNED_INT_128_ID: return Context.getUInt128Decl(); case PREDEF_DECL_OBJC_INSTANCETYPE_ID: return Context.getObjCInstanceTypeDecl(); case PREDEF_DECL_BUILTIN_VA_LIST_ID: return Context.getBuiltinVaListDecl(); case PREDEF_DECL_VA_LIST_TAG: return Context.getVaListTagDecl(); case PREDEF_DECL_BUILTIN_MS_VA_LIST_ID: return Context.getBuiltinMSVaListDecl(); case PREDEF_DECL_EXTERN_C_CONTEXT_ID: return Context.getExternCContextDecl(); case PREDEF_DECL_MAKE_INTEGER_SEQ_ID: return Context.getMakeIntegerSeqDecl(); case PREDEF_DECL_CF_CONSTANT_STRING_ID: return Context.getCFConstantStringDecl(); case PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID: return Context.getCFConstantStringTagDecl(); case PREDEF_DECL_TYPE_PACK_ELEMENT_ID: return Context.getTypePackElementDecl(); } llvm_unreachable("PredefinedDeclIDs unknown enum value"); } Decl *ASTReader::GetExistingDecl(DeclID ID) { if (ID < NUM_PREDEF_DECL_IDS) { Decl *D = getPredefinedDecl(Context, (PredefinedDeclIDs)ID); if (D) { // Track that we have merged the declaration with ID \p ID into the // pre-existing predefined declaration \p D. auto &Merged = KeyDecls[D->getCanonicalDecl()]; if (Merged.empty()) Merged.push_back(ID); } return D; } unsigned Index = ID - NUM_PREDEF_DECL_IDS; if (Index >= DeclsLoaded.size()) { assert(0 && "declaration ID out-of-range for AST file"); Error("declaration ID out-of-range for AST file"); return nullptr; } return DeclsLoaded[Index]; } Decl *ASTReader::GetDecl(DeclID ID) { if (ID < NUM_PREDEF_DECL_IDS) return GetExistingDecl(ID); unsigned Index = ID - NUM_PREDEF_DECL_IDS; if (Index >= DeclsLoaded.size()) { assert(0 && "declaration ID out-of-range for AST file"); Error("declaration ID out-of-range for AST file"); return nullptr; } if (!DeclsLoaded[Index]) { ReadDeclRecord(ID); if (DeserializationListener) DeserializationListener->DeclRead(ID, DeclsLoaded[Index]); } return DeclsLoaded[Index]; } DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M, DeclID GlobalID) { if (GlobalID < NUM_PREDEF_DECL_IDS) return GlobalID; GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID); assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); ModuleFile *Owner = I->second; llvm::DenseMap::iterator Pos = M.GlobalToLocalDeclIDs.find(Owner); if (Pos == M.GlobalToLocalDeclIDs.end()) return 0; return GlobalID - Owner->BaseDeclID + Pos->second; } serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F, const RecordData &Record, unsigned &Idx) { if (Idx >= Record.size()) { Error("Corrupted AST file"); return 0; } return getGlobalDeclID(F, Record[Idx++]); } /// \brief Resolve the offset of a statement into a statement. /// /// This operation will read a new statement from the external /// source each time it is called, and is meant to be used via a /// LazyOffsetPtr (which is used by Decls for the body of functions, etc). Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { // Switch case IDs are per Decl. ClearSwitchCaseIDs(); // Offset here is a global offset across the entire chain. RecordLocation Loc = getLocalBitOffset(Offset); Loc.F->DeclsCursor.JumpToBit(Loc.Offset); assert(NumCurrentElementsDeserializing == 0 && "should not be called while already deserializing"); Deserializing D(this); return ReadStmtFromStream(*Loc.F); } void ASTReader::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Decls) { bool PredefsVisited[NUM_PREDEF_DECL_IDS] = {}; auto Visit = [&] (ModuleFile *M, LexicalContents LexicalDecls) { assert(LexicalDecls.size() % 2 == 0 && "expected an even number of entries"); for (int I = 0, N = LexicalDecls.size(); I != N; I += 2) { auto K = (Decl::Kind)+LexicalDecls[I]; if (!IsKindWeWant(K)) continue; auto ID = (serialization::DeclID)+LexicalDecls[I + 1]; // Don't add predefined declarations to the lexical context more // than once. if (ID < NUM_PREDEF_DECL_IDS) { if (PredefsVisited[ID]) continue; PredefsVisited[ID] = true; } if (Decl *D = GetLocalDecl(*M, ID)) { assert(D->getKind() == K && "wrong kind for lexical decl"); if (!DC->isDeclInLexicalTraversal(D)) Decls.push_back(D); } } }; if (isa(DC)) { for (auto Lexical : TULexicalDecls) Visit(Lexical.first, Lexical.second); } else { auto I = LexicalDecls.find(DC); if (I != LexicalDecls.end()) Visit(I->second.first, I->second.second); } ++NumLexicalDeclContextsRead; } namespace { class DeclIDComp { ASTReader &Reader; ModuleFile &Mod; public: DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {} bool operator()(LocalDeclID L, LocalDeclID R) const { SourceLocation LHS = getLocation(L); SourceLocation RHS = getLocation(R); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } bool operator()(SourceLocation LHS, LocalDeclID R) const { SourceLocation RHS = getLocation(R); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } bool operator()(LocalDeclID L, SourceLocation RHS) const { SourceLocation LHS = getLocation(L); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } SourceLocation getLocation(LocalDeclID ID) const { return Reader.getSourceManager().getFileLoc( Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID))); } }; } // end anonymous namespace void ASTReader::FindFileRegionDecls(FileID File, unsigned Offset, unsigned Length, SmallVectorImpl &Decls) { SourceManager &SM = getSourceManager(); llvm::DenseMap::iterator I = FileDeclIDs.find(File); if (I == FileDeclIDs.end()) return; FileDeclsInfo &DInfo = I->second; if (DInfo.Decls.empty()) return; SourceLocation BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset); SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length); DeclIDComp DIDComp(*this, *DInfo.Mod); ArrayRef::iterator BeginIt = std::lower_bound(DInfo.Decls.begin(), DInfo.Decls.end(), BeginLoc, DIDComp); if (BeginIt != DInfo.Decls.begin()) --BeginIt; // If we are pointing at a top-level decl inside an objc container, we need // to backtrack until we find it otherwise we will fail to report that the // region overlaps with an objc container. while (BeginIt != DInfo.Decls.begin() && GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt)) ->isTopLevelDeclInObjCContainer()) --BeginIt; ArrayRef::iterator EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(), EndLoc, DIDComp); if (EndIt != DInfo.Decls.end()) ++EndIt; for (ArrayRef::iterator DIt = BeginIt; DIt != EndIt; ++DIt) Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt))); } bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { assert(DC->hasExternalVisibleStorage() && DC == DC->getPrimaryContext() && "DeclContext has no visible decls in storage"); if (!Name) return false; auto It = Lookups.find(DC); if (It == Lookups.end()) return false; Deserializing LookupResults(this); // Load the list of declarations. SmallVector Decls; for (DeclID ID : It->second.Table.find(Name)) { NamedDecl *ND = cast(GetDecl(ID)); if (ND->getDeclName() == Name) Decls.push_back(ND); } ++NumVisibleDeclContextsRead; SetExternalVisibleDeclsForName(DC, Name, Decls); return !Decls.empty(); } void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { if (!DC->hasExternalVisibleStorage()) return; auto It = Lookups.find(DC); assert(It != Lookups.end() && "have external visible storage but no lookup tables"); DeclsMap Decls; for (DeclID ID : It->second.Table.findAll()) { NamedDecl *ND = cast(GetDecl(ID)); Decls[ND->getDeclName()].push_back(ND); } ++NumVisibleDeclContextsRead; for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { SetExternalVisibleDeclsForName(DC, I->first, I->second); } const_cast(DC)->setHasExternalVisibleStorage(false); } const serialization::reader::DeclContextLookupTable * ASTReader::getLoadedLookupTables(DeclContext *Primary) const { auto I = Lookups.find(Primary); return I == Lookups.end() ? nullptr : &I->second; } /// \brief Under non-PCH compilation the consumer receives the objc methods /// before receiving the implementation, and codegen depends on this. /// We simulate this by deserializing and passing to consumer the methods of the /// implementation before passing the deserialized implementation decl. static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD, ASTConsumer *Consumer) { assert(ImplD && Consumer); for (auto *I : ImplD->methods()) Consumer->HandleInterestingDecl(DeclGroupRef(I)); Consumer->HandleInterestingDecl(DeclGroupRef(ImplD)); } void ASTReader::PassInterestingDeclToConsumer(Decl *D) { if (ObjCImplDecl *ImplD = dyn_cast(D)) PassObjCImplDeclToConsumer(ImplD, Consumer); else Consumer->HandleInterestingDecl(DeclGroupRef(D)); } void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) { this->Consumer = Consumer; if (Consumer) PassInterestingDeclsToConsumer(); if (DeserializationListener) DeserializationListener->ReaderInitialized(this); } void ASTReader::PrintStats() { std::fprintf(stderr, "*** AST File Statistics:\n"); unsigned NumTypesLoaded = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(), QualType()); unsigned NumDeclsLoaded = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(), (Decl *)nullptr); unsigned NumIdentifiersLoaded = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(), IdentifiersLoaded.end(), (IdentifierInfo *)nullptr); unsigned NumMacrosLoaded = MacrosLoaded.size() - std::count(MacrosLoaded.begin(), MacrosLoaded.end(), (MacroInfo *)nullptr); unsigned NumSelectorsLoaded = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(), SelectorsLoaded.end(), Selector()); if (unsigned TotalNumSLocEntries = getTotalNumSLocs()) std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n", NumSLocEntriesRead, TotalNumSLocEntries, ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100)); if (!TypesLoaded.empty()) std::fprintf(stderr, " %u/%u types read (%f%%)\n", NumTypesLoaded, (unsigned)TypesLoaded.size(), ((float)NumTypesLoaded/TypesLoaded.size() * 100)); if (!DeclsLoaded.empty()) std::fprintf(stderr, " %u/%u declarations read (%f%%)\n", NumDeclsLoaded, (unsigned)DeclsLoaded.size(), ((float)NumDeclsLoaded/DeclsLoaded.size() * 100)); if (!IdentifiersLoaded.empty()) std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n", NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(), ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100)); if (!MacrosLoaded.empty()) std::fprintf(stderr, " %u/%u macros read (%f%%)\n", NumMacrosLoaded, (unsigned)MacrosLoaded.size(), ((float)NumMacrosLoaded/MacrosLoaded.size() * 100)); if (!SelectorsLoaded.empty()) std::fprintf(stderr, " %u/%u selectors read (%f%%)\n", NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(), ((float)NumSelectorsLoaded/SelectorsLoaded.size() * 100)); if (TotalNumStatements) std::fprintf(stderr, " %u/%u statements read (%f%%)\n", NumStatementsRead, TotalNumStatements, ((float)NumStatementsRead/TotalNumStatements * 100)); if (TotalNumMacros) std::fprintf(stderr, " %u/%u macros read (%f%%)\n", NumMacrosRead, TotalNumMacros, ((float)NumMacrosRead/TotalNumMacros * 100)); if (TotalLexicalDeclContexts) std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n", NumLexicalDeclContextsRead, TotalLexicalDeclContexts, ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts * 100)); if (TotalVisibleDeclContexts) std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n", NumVisibleDeclContextsRead, TotalVisibleDeclContexts, ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts * 100)); if (TotalNumMethodPoolEntries) { std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n", NumMethodPoolEntriesRead, TotalNumMethodPoolEntries, ((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries * 100)); } if (NumMethodPoolLookups) { std::fprintf(stderr, " %u/%u method pool lookups succeeded (%f%%)\n", NumMethodPoolHits, NumMethodPoolLookups, ((float)NumMethodPoolHits/NumMethodPoolLookups * 100.0)); } if (NumMethodPoolTableLookups) { std::fprintf(stderr, " %u/%u method pool table lookups succeeded (%f%%)\n", NumMethodPoolTableHits, NumMethodPoolTableLookups, ((float)NumMethodPoolTableHits/NumMethodPoolTableLookups * 100.0)); } if (NumIdentifierLookupHits) { std::fprintf(stderr, " %u / %u identifier table lookups succeeded (%f%%)\n", NumIdentifierLookupHits, NumIdentifierLookups, (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups); } if (GlobalIndex) { std::fprintf(stderr, "\n"); GlobalIndex->printStats(); } std::fprintf(stderr, "\n"); dump(); std::fprintf(stderr, "\n"); } template LLVM_DUMP_METHOD static void dumpModuleIDMap(StringRef Name, const ContinuousRangeMap &Map) { if (Map.begin() == Map.end()) return; typedef ContinuousRangeMap MapType; llvm::errs() << Name << ":\n"; for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); I != IEnd; ++I) { llvm::errs() << " " << I->first << " -> " << I->second->FileName << "\n"; } } LLVM_DUMP_METHOD void ASTReader::dump() { llvm::errs() << "*** PCH/ModuleFile Remappings:\n"; dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap); dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap); dumpModuleIDMap("Global type map", GlobalTypeMap); dumpModuleIDMap("Global declaration map", GlobalDeclMap); dumpModuleIDMap("Global identifier map", GlobalIdentifierMap); dumpModuleIDMap("Global macro map", GlobalMacroMap); dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap); dumpModuleIDMap("Global selector map", GlobalSelectorMap); dumpModuleIDMap("Global preprocessed entity map", GlobalPreprocessedEntityMap); llvm::errs() << "\n*** PCH/Modules Loaded:"; for (ModuleFile &M : ModuleMgr) M.dump(); } /// Return the amount of memory used by memory buffers, breaking down /// by heap-backed versus mmap'ed memory. void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { for (ModuleFile &I : ModuleMgr) { if (llvm::MemoryBuffer *buf = I.Buffer) { size_t bytes = buf->getBufferSize(); switch (buf->getBufferKind()) { case llvm::MemoryBuffer::MemoryBuffer_Malloc: sizes.malloc_bytes += bytes; break; case llvm::MemoryBuffer::MemoryBuffer_MMap: sizes.mmap_bytes += bytes; break; } } } } void ASTReader::InitializeSema(Sema &S) { SemaObj = &S; S.addExternalSource(this); // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (uint64_t ID : PreloadedDeclIDs) { NamedDecl *D = cast(GetDecl(ID)); pushExternalDeclIntoScope(D, D->getDeclName()); } PreloadedDeclIDs.clear(); // FIXME: What happens if these are changed by a module import? if (!FPPragmaOptions.empty()) { assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS"); SemaObj->FPFeatures = FPOptions(FPPragmaOptions[0]); } SemaObj->OpenCLFeatures.copy(OpenCLExtensions); SemaObj->OpenCLTypeExtMap = OpenCLTypeExtMap; SemaObj->OpenCLDeclExtMap = OpenCLDeclExtMap; UpdateSema(); } void ASTReader::UpdateSema() { assert(SemaObj && "no Sema to update"); // Load the offsets of the declarations that Sema references. // They will be lazily deserialized when needed. if (!SemaDeclRefs.empty()) { assert(SemaDeclRefs.size() % 3 == 0); for (unsigned I = 0; I != SemaDeclRefs.size(); I += 3) { if (!SemaObj->StdNamespace) SemaObj->StdNamespace = SemaDeclRefs[I]; if (!SemaObj->StdBadAlloc) SemaObj->StdBadAlloc = SemaDeclRefs[I+1]; if (!SemaObj->StdAlignValT) SemaObj->StdAlignValT = SemaDeclRefs[I+2]; } SemaDeclRefs.clear(); } // Update the state of pragmas. Use the same API as if we had encountered the // pragma in the source. if(OptimizeOffPragmaLocation.isValid()) SemaObj->ActOnPragmaOptimize(/* IsOn = */ false, OptimizeOffPragmaLocation); if (PragmaMSStructState != -1) SemaObj->ActOnPragmaMSStruct((PragmaMSStructKind)PragmaMSStructState); if (PointersToMembersPragmaLocation.isValid()) { SemaObj->ActOnPragmaMSPointersToMembers( (LangOptions::PragmaMSPointersToMembersKind) PragmaMSPointersToMembersState, PointersToMembersPragmaLocation); } SemaObj->ForceCUDAHostDeviceDepth = ForceCUDAHostDeviceDepth; if (PragmaPackCurrentValue) { // The bottom of the stack might have a default value. It must be adjusted // to the current value to ensure that the packing state is preserved after // popping entries that were included/imported from a PCH/module. bool DropFirst = false; if (!PragmaPackStack.empty() && PragmaPackStack.front().Location.isInvalid()) { assert(PragmaPackStack.front().Value == SemaObj->PackStack.DefaultValue && "Expected a default alignment value"); SemaObj->PackStack.Stack.emplace_back( PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue, SemaObj->PackStack.CurrentPragmaLocation); DropFirst = true; } for (const auto &Entry : llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0)) SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value, Entry.Location); if (PragmaPackCurrentLocation.isInvalid()) { assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue && "Expected a default alignment value"); // Keep the current values. } else { SemaObj->PackStack.CurrentValue = *PragmaPackCurrentValue; SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation; } } } IdentifierInfo *ASTReader::get(StringRef Name) { // Note that we are loading an identifier. Deserializing AnIdentifier(this); IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0, NumIdentifierLookups, NumIdentifierLookupHits); // We don't need to do identifier table lookups in C++ modules (we preload // all interesting declarations, and don't need to use the scope for name // lookups). Perform the lookup in PCH files, though, since we don't build // a complete initial identifier table if we're carrying on from a PCH. if (Context.getLangOpts().CPlusPlus) { for (auto F : ModuleMgr.pch_modules()) if (Visitor(*F)) break; } else { // If there is a global index, look there first to determine which modules // provably do not have any results for this identifier. GlobalModuleIndex::HitSet Hits; GlobalModuleIndex::HitSet *HitsPtr = nullptr; if (!loadGlobalIndex()) { if (GlobalIndex->lookupIdentifier(Name, Hits)) { HitsPtr = &Hits; } } ModuleMgr.visit(Visitor, HitsPtr); } IdentifierInfo *II = Visitor.getIdentifierInfo(); markIdentifierUpToDate(II); return II; } namespace clang { /// \brief An identifier-lookup iterator that enumerates all of the /// identifiers stored within a set of AST files. class ASTIdentifierIterator : public IdentifierIterator { /// \brief The AST reader whose identifiers are being enumerated. const ASTReader &Reader; /// \brief The current index into the chain of AST files stored in /// the AST reader. unsigned Index; /// \brief The current position within the identifier lookup table /// of the current AST file. ASTIdentifierLookupTable::key_iterator Current; /// \brief The end position within the identifier lookup table of /// the current AST file. ASTIdentifierLookupTable::key_iterator End; /// \brief Whether to skip any modules in the ASTReader. bool SkipModules; public: explicit ASTIdentifierIterator(const ASTReader &Reader, bool SkipModules = false); StringRef Next() override; }; } // end namespace clang ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader, bool SkipModules) : Reader(Reader), Index(Reader.ModuleMgr.size()), SkipModules(SkipModules) { } StringRef ASTIdentifierIterator::Next() { while (Current == End) { // If we have exhausted all of our AST files, we're done. if (Index == 0) return StringRef(); --Index; ModuleFile &F = Reader.ModuleMgr[Index]; if (SkipModules && F.isModule()) continue; ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)F.IdentifierLookupTable; Current = IdTable->key_begin(); End = IdTable->key_end(); } // We have any identifiers remaining in the current AST file; return // the next one. StringRef Result = *Current; ++Current; return Result; } namespace { /// A utility for appending two IdentifierIterators. class ChainedIdentifierIterator : public IdentifierIterator { std::unique_ptr Current; std::unique_ptr Queued; public: ChainedIdentifierIterator(std::unique_ptr First, std::unique_ptr Second) : Current(std::move(First)), Queued(std::move(Second)) {} StringRef Next() override { if (!Current) return StringRef(); StringRef result = Current->Next(); if (!result.empty()) return result; // Try the queued iterator, which may itself be empty. Current.reset(); std::swap(Current, Queued); return Next(); } }; } // end anonymous namespace. IdentifierIterator *ASTReader::getIdentifiers() { if (!loadGlobalIndex()) { std::unique_ptr ReaderIter( new ASTIdentifierIterator(*this, /*SkipModules=*/true)); std::unique_ptr ModulesIter( GlobalIndex->createIdentifierIterator()); return new ChainedIdentifierIterator(std::move(ReaderIter), std::move(ModulesIter)); } return new ASTIdentifierIterator(*this); } namespace clang { namespace serialization { class ReadMethodPoolVisitor { ASTReader &Reader; Selector Sel; unsigned PriorGeneration; unsigned InstanceBits; unsigned FactoryBits; bool InstanceHasMoreThanOneDecl; bool FactoryHasMoreThanOneDecl; SmallVector InstanceMethods; SmallVector FactoryMethods; public: ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, unsigned PriorGeneration) : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration), InstanceBits(0), FactoryBits(0), InstanceHasMoreThanOneDecl(false), FactoryHasMoreThanOneDecl(false) {} bool operator()(ModuleFile &M) { if (!M.SelectorLookupTable) return false; // If we've already searched this module file, skip it now. if (M.Generation <= PriorGeneration) return true; ++Reader.NumMethodPoolTableLookups; ASTSelectorLookupTable *PoolTable = (ASTSelectorLookupTable*)M.SelectorLookupTable; ASTSelectorLookupTable::iterator Pos = PoolTable->find(Sel); if (Pos == PoolTable->end()) return false; ++Reader.NumMethodPoolTableHits; ++Reader.NumSelectorsRead; // FIXME: Not quite happy with the statistics here. We probably should // disable this tracking when called via LoadSelector. // Also, should entries without methods count as misses? ++Reader.NumMethodPoolEntriesRead; ASTSelectorLookupTrait::data_type Data = *Pos; if (Reader.DeserializationListener) Reader.DeserializationListener->SelectorRead(Data.ID, Sel); InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); InstanceBits = Data.InstanceBits; FactoryBits = Data.FactoryBits; InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl; FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl; return true; } /// \brief Retrieve the instance methods found by this visitor. ArrayRef getInstanceMethods() const { return InstanceMethods; } /// \brief Retrieve the instance methods found by this visitor. ArrayRef getFactoryMethods() const { return FactoryMethods; } unsigned getInstanceBits() const { return InstanceBits; } unsigned getFactoryBits() const { return FactoryBits; } bool instanceHasMoreThanOneDecl() const { return InstanceHasMoreThanOneDecl; } bool factoryHasMoreThanOneDecl() const { return FactoryHasMoreThanOneDecl; } }; } // end namespace serialization } // end namespace clang /// \brief Add the given set of methods to the method list. static void addMethodsToPool(Sema &S, ArrayRef Methods, ObjCMethodList &List) { for (unsigned I = 0, N = Methods.size(); I != N; ++I) { S.addMethodToGlobalList(&List, Methods[I]); } } void ASTReader::ReadMethodPool(Selector Sel) { // Get the selector generation and update it to the current generation. unsigned &Generation = SelectorGeneration[Sel]; unsigned PriorGeneration = Generation; Generation = getGeneration(); SelectorOutOfDate[Sel] = false; // Search for methods defined with this selector. ++NumMethodPoolLookups; ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration); ModuleMgr.visit(Visitor); if (Visitor.getInstanceMethods().empty() && Visitor.getFactoryMethods().empty()) return; ++NumMethodPoolHits; if (!getSema()) return; Sema &S = *getSema(); Sema::GlobalMethodPool::iterator Pos = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first; Pos->second.first.setBits(Visitor.getInstanceBits()); Pos->second.first.setHasMoreThanOneDecl(Visitor.instanceHasMoreThanOneDecl()); Pos->second.second.setBits(Visitor.getFactoryBits()); Pos->second.second.setHasMoreThanOneDecl(Visitor.factoryHasMoreThanOneDecl()); // Add methods to the global pool *after* setting hasMoreThanOneDecl, since // when building a module we keep every method individually and may need to // update hasMoreThanOneDecl as we add the methods. addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); } void ASTReader::updateOutOfDateSelector(Selector Sel) { if (SelectorOutOfDate[Sel]) ReadMethodPool(Sel); } void ASTReader::ReadKnownNamespaces( SmallVectorImpl &Namespaces) { Namespaces.clear(); for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) { if (NamespaceDecl *Namespace = dyn_cast_or_null(GetDecl(KnownNamespaces[I]))) Namespaces.push_back(Namespace); } } void ASTReader::ReadUndefinedButUsed( llvm::MapVector &Undefined) { for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) { NamedDecl *D = cast(GetDecl(UndefinedButUsed[Idx++])); SourceLocation Loc = SourceLocation::getFromRawEncoding(UndefinedButUsed[Idx++]); Undefined.insert(std::make_pair(D, Loc)); } } void ASTReader::ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector, 4>> & Exprs) { for (unsigned Idx = 0, N = DelayedDeleteExprs.size(); Idx != N;) { FieldDecl *FD = cast(GetDecl(DelayedDeleteExprs[Idx++])); uint64_t Count = DelayedDeleteExprs[Idx++]; for (uint64_t C = 0; C < Count; ++C) { SourceLocation DeleteLoc = SourceLocation::getFromRawEncoding(DelayedDeleteExprs[Idx++]); const bool IsArrayForm = DelayedDeleteExprs[Idx++]; Exprs[FD].push_back(std::make_pair(DeleteLoc, IsArrayForm)); } } } void ASTReader::ReadTentativeDefinitions( SmallVectorImpl &TentativeDefs) { for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { VarDecl *Var = dyn_cast_or_null(GetDecl(TentativeDefinitions[I])); if (Var) TentativeDefs.push_back(Var); } TentativeDefinitions.clear(); } void ASTReader::ReadUnusedFileScopedDecls( SmallVectorImpl &Decls) { for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) { DeclaratorDecl *D = dyn_cast_or_null(GetDecl(UnusedFileScopedDecls[I])); if (D) Decls.push_back(D); } UnusedFileScopedDecls.clear(); } void ASTReader::ReadDelegatingConstructors( SmallVectorImpl &Decls) { for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) { CXXConstructorDecl *D = dyn_cast_or_null(GetDecl(DelegatingCtorDecls[I])); if (D) Decls.push_back(D); } DelegatingCtorDecls.clear(); } void ASTReader::ReadExtVectorDecls(SmallVectorImpl &Decls) { for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) { TypedefNameDecl *D = dyn_cast_or_null(GetDecl(ExtVectorDecls[I])); if (D) Decls.push_back(D); } ExtVectorDecls.clear(); } void ASTReader::ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector &Decls) { for (unsigned I = 0, N = UnusedLocalTypedefNameCandidates.size(); I != N; ++I) { TypedefNameDecl *D = dyn_cast_or_null( GetDecl(UnusedLocalTypedefNameCandidates[I])); if (D) Decls.insert(D); } UnusedLocalTypedefNameCandidates.clear(); } void ASTReader::ReadReferencedSelectors( SmallVectorImpl > &Sels) { if (ReferencedSelectorsData.empty()) return; // If there are @selector references added them to its pool. This is for // implementation of -Wselector. unsigned int DataSize = ReferencedSelectorsData.size()-1; unsigned I = 0; while (I < DataSize) { Selector Sel = DecodeSelector(ReferencedSelectorsData[I++]); SourceLocation SelLoc = SourceLocation::getFromRawEncoding(ReferencedSelectorsData[I++]); Sels.push_back(std::make_pair(Sel, SelLoc)); } ReferencedSelectorsData.clear(); } void ASTReader::ReadWeakUndeclaredIdentifiers( SmallVectorImpl > &WeakIDs) { if (WeakUndeclaredIdentifiers.empty()) return; for (unsigned I = 0, N = WeakUndeclaredIdentifiers.size(); I < N; /*none*/) { IdentifierInfo *WeakId = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]); IdentifierInfo *AliasId = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]); SourceLocation Loc = SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]); bool Used = WeakUndeclaredIdentifiers[I++]; WeakInfo WI(AliasId, Loc); WI.setUsed(Used); WeakIDs.push_back(std::make_pair(WeakId, WI)); } WeakUndeclaredIdentifiers.clear(); } void ASTReader::ReadUsedVTables(SmallVectorImpl &VTables) { for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) { ExternalVTableUse VT; VT.Record = dyn_cast_or_null(GetDecl(VTableUses[Idx++])); VT.Location = SourceLocation::getFromRawEncoding(VTableUses[Idx++]); VT.DefinitionRequired = VTableUses[Idx++]; VTables.push_back(VT); } VTableUses.clear(); } void ASTReader::ReadPendingInstantiations( SmallVectorImpl > &Pending) { for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) { ValueDecl *D = cast(GetDecl(PendingInstantiations[Idx++])); SourceLocation Loc = SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]); Pending.push_back(std::make_pair(D, Loc)); } PendingInstantiations.clear(); } void ASTReader::ReadLateParsedTemplates( llvm::MapVector> &LPTMap) { for (unsigned Idx = 0, N = LateParsedTemplates.size(); Idx < N; /* In loop */) { FunctionDecl *FD = cast(GetDecl(LateParsedTemplates[Idx++])); auto LT = llvm::make_unique(); LT->D = GetDecl(LateParsedTemplates[Idx++]); ModuleFile *F = getOwningModuleFile(LT->D); assert(F && "No module"); unsigned TokN = LateParsedTemplates[Idx++]; LT->Toks.reserve(TokN); for (unsigned T = 0; T < TokN; ++T) LT->Toks.push_back(ReadToken(*F, LateParsedTemplates, Idx)); LPTMap.insert(std::make_pair(FD, std::move(LT))); } LateParsedTemplates.clear(); } void ASTReader::LoadSelector(Selector Sel) { // It would be complicated to avoid reading the methods anyway. So don't. ReadMethodPool(Sel); } void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) { assert(ID && "Non-zero identifier ID required"); assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range"); IdentifiersLoaded[ID - 1] = II; if (DeserializationListener) DeserializationListener->IdentifierRead(ID, II); } /// \brief Set the globally-visible declarations associated with the given /// identifier. /// /// If the AST reader is currently in a state where the given declaration IDs /// cannot safely be resolved, they are queued until it is safe to resolve /// them. /// /// \param II an IdentifierInfo that refers to one or more globally-visible /// declarations. /// /// \param DeclIDs the set of declaration IDs with the name @p II that are /// visible at global scope. /// /// \param Decls if non-null, this vector will be populated with the set of /// deserialized declarations. These declarations will not be pushed into /// scope. void ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, const SmallVectorImpl &DeclIDs, SmallVectorImpl *Decls) { if (NumCurrentElementsDeserializing && !Decls) { PendingIdentifierInfos[II].append(DeclIDs.begin(), DeclIDs.end()); return; } for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) { if (!SemaObj) { // Queue this declaration so that it will be added to the // translation unit scope and identifier's declaration chain // once a Sema object is known. PreloadedDeclIDs.push_back(DeclIDs[I]); continue; } NamedDecl *D = cast(GetDecl(DeclIDs[I])); // If we're simply supposed to record the declarations, do so now. if (Decls) { Decls->push_back(D); continue; } // Introduce this declaration into the translation-unit scope // and add it to the declaration chain for this identifier, so // that (unqualified) name lookup will find it. pushExternalDeclIntoScope(D, II); } } IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) { if (ID == 0) return nullptr; if (IdentifiersLoaded.empty()) { Error("no identifier table in AST file"); return nullptr; } ID -= 1; if (!IdentifiersLoaded[ID]) { GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1); assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map"); ModuleFile *M = I->second; unsigned Index = ID - M->BaseIdentifierID; const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index]; // All of the strings in the AST file are preceded by a 16-bit length. // Extract that 16-bit length to avoid having to execute strlen(). // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as // unsigned integers. This is important to avoid integer overflow when // we cast them to 'unsigned'. const unsigned char *StrLenPtr = (const unsigned char*) Str - 2; unsigned StrLen = (((unsigned) StrLenPtr[0]) | (((unsigned) StrLenPtr[1]) << 8)) - 1; auto &II = PP.getIdentifierTable().get(StringRef(Str, StrLen)); IdentifiersLoaded[ID] = &II; markIdentifierFromAST(*this, II); if (DeserializationListener) DeserializationListener->IdentifierRead(ID + 1, &II); } return IdentifiersLoaded[ID]; } IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, unsigned LocalID) { return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID)); } IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) { if (LocalID < NUM_PREDEF_IDENT_IDS) return LocalID; if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::iterator I = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS); assert(I != M.IdentifierRemap.end() && "Invalid index into identifier index remap"); return LocalID + I->second; } MacroInfo *ASTReader::getMacro(MacroID ID) { if (ID == 0) return nullptr; if (MacrosLoaded.empty()) { Error("no macro table in AST file"); return nullptr; } ID -= NUM_PREDEF_MACRO_IDS; if (!MacrosLoaded[ID]) { GlobalMacroMapType::iterator I = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS); assert(I != GlobalMacroMap.end() && "Corrupted global macro map"); ModuleFile *M = I->second; unsigned Index = ID - M->BaseMacroID; MacrosLoaded[ID] = ReadMacroRecord(*M, M->MacroOffsets[Index]); if (DeserializationListener) DeserializationListener->MacroRead(ID + NUM_PREDEF_MACRO_IDS, MacrosLoaded[ID]); } return MacrosLoaded[ID]; } MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) { if (LocalID < NUM_PREDEF_MACRO_IDS) return LocalID; if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::iterator I = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS); assert(I != M.MacroRemap.end() && "Invalid index into macro index remap"); return LocalID + I->second; } serialization::SubmoduleID ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) { if (LocalID < NUM_PREDEF_SUBMODULE_IDS) return LocalID; if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::iterator I = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS); assert(I != M.SubmoduleRemap.end() && "Invalid index into submodule index remap"); return LocalID + I->second; } Module *ASTReader::getSubmodule(SubmoduleID GlobalID) { if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) { assert(GlobalID == 0 && "Unhandled global submodule ID"); return nullptr; } if (GlobalID > SubmodulesLoaded.size()) { Error("submodule ID out of range in AST file"); return nullptr; } return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS]; } Module *ASTReader::getModule(unsigned ID) { return getSubmodule(ID); } ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) { if (ID & 1) { // It's a module, look it up by submodule ID. auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(F, ID >> 1)); return I == GlobalSubmoduleMap.end() ? nullptr : I->second; } else { // It's a prefix (preamble, PCH, ...). Look it up by index. unsigned IndexFromEnd = ID >> 1; assert(IndexFromEnd && "got reference to unknown module file"); return getModuleManager().pch_modules().end()[-IndexFromEnd]; } } unsigned ASTReader::getModuleFileID(ModuleFile *F) { if (!F) return 1; // For a file representing a module, use the submodule ID of the top-level // module as the file ID. For any other kind of file, the number of such // files loaded beforehand will be the same on reload. // FIXME: Is this true even if we have an explicit module file and a PCH? if (F->isModule()) return ((F->BaseSubmoduleID + NUM_PREDEF_SUBMODULE_IDS) << 1) | 1; auto PCHModules = getModuleManager().pch_modules(); auto I = std::find(PCHModules.begin(), PCHModules.end(), F); assert(I != PCHModules.end() && "emitting reference to unknown file"); return (I - PCHModules.end()) << 1; } llvm::Optional ASTReader::getSourceDescriptor(unsigned ID) { if (const Module *M = getSubmodule(ID)) return ExternalASTSource::ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. // Chained PCH are not suported. const auto &PCHChain = ModuleMgr.pch_modules(); if (std::distance(std::begin(PCHChain), std::end(PCHChain))) { ModuleFile &MF = ModuleMgr.getPrimaryModule(); StringRef ModuleName = llvm::sys::path::filename(MF.OriginalSourceFileName); StringRef FileName = llvm::sys::path::filename(MF.FileName); return ASTReader::ASTSourceDescriptor(ModuleName, MF.OriginalDir, FileName, MF.Signature); } return None; } ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) { auto I = BodySource.find(FD); if (I == BodySource.end()) return EK_ReplyHazy; return I->second ? EK_Never : EK_Always; } Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { return DecodeSelector(getGlobalSelectorID(M, LocalID)); } Selector ASTReader::DecodeSelector(serialization::SelectorID ID) { if (ID == 0) return Selector(); if (ID > SelectorsLoaded.size()) { Error("selector ID out of range in AST file"); return Selector(); } if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == nullptr) { // Load this selector from the selector table. GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID); assert(I != GlobalSelectorMap.end() && "Corrupted global selector map"); ModuleFile &M = *I->second; ASTSelectorLookupTrait Trait(*this, M); unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS; SelectorsLoaded[ID - 1] = Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0); if (DeserializationListener) DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]); } return SelectorsLoaded[ID - 1]; } Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) { return DecodeSelector(ID); } uint32_t ASTReader::GetNumExternalSelectors() { // ID 0 (the null selector) is considered an external selector. return getTotalNumSelectors() + 1; } serialization::SelectorID ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { if (LocalID < NUM_PREDEF_SELECTOR_IDS) return LocalID; if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::iterator I = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS); assert(I != M.SelectorRemap.end() && "Invalid index into selector index remap"); return LocalID + I->second; } DeclarationName ASTReader::ReadDeclarationName(ModuleFile &F, const RecordData &Record, unsigned &Idx) { DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; switch (Kind) { case DeclarationName::Identifier: return DeclarationName(GetIdentifierInfo(F, Record, Idx)); case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: return DeclarationName(ReadSelector(F, Record, Idx)); case DeclarationName::CXXConstructorName: return Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(readType(F, Record, Idx))); case DeclarationName::CXXDestructorName: return Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(readType(F, Record, Idx))); case DeclarationName::CXXDeductionGuideName: return Context.DeclarationNames.getCXXDeductionGuideName( ReadDeclAs(F, Record, Idx)); case DeclarationName::CXXConversionFunctionName: return Context.DeclarationNames.getCXXConversionFunctionName( Context.getCanonicalType(readType(F, Record, Idx))); case DeclarationName::CXXOperatorName: return Context.DeclarationNames.getCXXOperatorName( (OverloadedOperatorKind)Record[Idx++]); case DeclarationName::CXXLiteralOperatorName: return Context.DeclarationNames.getCXXLiteralOperatorName( GetIdentifierInfo(F, Record, Idx)); case DeclarationName::CXXUsingDirective: return DeclarationName::getUsingDirectiveName(); } llvm_unreachable("Invalid NameKind!"); } void ASTReader::ReadDeclarationNameLoc(ModuleFile &F, DeclarationNameLoc &DNLoc, DeclarationName Name, const RecordData &Record, unsigned &Idx) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx); break; case DeclarationName::CXXOperatorName: DNLoc.CXXOperatorName.BeginOpNameLoc = ReadSourceLocation(F, Record, Idx).getRawEncoding(); DNLoc.CXXOperatorName.EndOpNameLoc = ReadSourceLocation(F, Record, Idx).getRawEncoding(); break; case DeclarationName::CXXLiteralOperatorName: DNLoc.CXXLiteralOperatorName.OpNameLoc = ReadSourceLocation(F, Record, Idx).getRawEncoding(); break; case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: case DeclarationName::CXXDeductionGuideName: break; } } void ASTReader::ReadDeclarationNameInfo(ModuleFile &F, DeclarationNameInfo &NameInfo, const RecordData &Record, unsigned &Idx) { NameInfo.setName(ReadDeclarationName(F, Record, Idx)); NameInfo.setLoc(ReadSourceLocation(F, Record, Idx)); DeclarationNameLoc DNLoc; ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx); NameInfo.setInfo(DNLoc); } void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, const RecordData &Record, unsigned &Idx) { Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx); unsigned NumTPLists = Record[Idx++]; Info.NumTemplParamLists = NumTPLists; if (NumTPLists) { Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists]; for (unsigned i = 0; i != NumTPLists; ++i) Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx); } } TemplateName ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record, unsigned &Idx) { TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; switch (Kind) { case TemplateName::Template: return TemplateName(ReadDeclAs(F, Record, Idx)); case TemplateName::OverloadedTemplate: { unsigned size = Record[Idx++]; UnresolvedSet<8> Decls; while (size--) Decls.addDecl(ReadDeclAs(F, Record, Idx)); return Context.getOverloadedTemplateName(Decls.begin(), Decls.end()); } case TemplateName::QualifiedTemplate: { NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); bool hasTemplKeyword = Record[Idx++]; TemplateDecl *Template = ReadDeclAs(F, Record, Idx); return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template); } case TemplateName::DependentTemplate: { NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); if (Record[Idx++]) // isIdentifier return Context.getDependentTemplateName(NNS, GetIdentifierInfo(F, Record, Idx)); return Context.getDependentTemplateName(NNS, (OverloadedOperatorKind)Record[Idx++]); } case TemplateName::SubstTemplateTemplateParm: { TemplateTemplateParmDecl *param = ReadDeclAs(F, Record, Idx); if (!param) return TemplateName(); TemplateName replacement = ReadTemplateName(F, Record, Idx); return Context.getSubstTemplateTemplateParm(param, replacement); } case TemplateName::SubstTemplateTemplateParmPack: { TemplateTemplateParmDecl *Param = ReadDeclAs(F, Record, Idx); if (!Param) return TemplateName(); TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx); if (ArgPack.getKind() != TemplateArgument::Pack) return TemplateName(); return Context.getSubstTemplateTemplateParmPack(Param, ArgPack); } } llvm_unreachable("Unhandled template name kind!"); } TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F, const RecordData &Record, unsigned &Idx, bool Canonicalize) { if (Canonicalize) { // The caller wants a canonical template argument. Sometimes the AST only // wants template arguments in canonical form (particularly as the template // argument lists of template specializations) so ensure we preserve that // canonical form across serialization. TemplateArgument Arg = ReadTemplateArgument(F, Record, Idx, false); return Context.getCanonicalTemplateArgument(Arg); } TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++]; switch (Kind) { case TemplateArgument::Null: return TemplateArgument(); case TemplateArgument::Type: return TemplateArgument(readType(F, Record, Idx)); case TemplateArgument::Declaration: { ValueDecl *D = ReadDeclAs(F, Record, Idx); return TemplateArgument(D, readType(F, Record, Idx)); } case TemplateArgument::NullPtr: return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true); case TemplateArgument::Integral: { llvm::APSInt Value = ReadAPSInt(Record, Idx); QualType T = readType(F, Record, Idx); return TemplateArgument(Context, Value, T); } case TemplateArgument::Template: return TemplateArgument(ReadTemplateName(F, Record, Idx)); case TemplateArgument::TemplateExpansion: { TemplateName Name = ReadTemplateName(F, Record, Idx); Optional NumTemplateExpansions; if (unsigned NumExpansions = Record[Idx++]) NumTemplateExpansions = NumExpansions - 1; return TemplateArgument(Name, NumTemplateExpansions); } case TemplateArgument::Expression: return TemplateArgument(ReadExpr(F)); case TemplateArgument::Pack: { unsigned NumArgs = Record[Idx++]; TemplateArgument *Args = new (Context) TemplateArgument[NumArgs]; for (unsigned I = 0; I != NumArgs; ++I) Args[I] = ReadTemplateArgument(F, Record, Idx); return TemplateArgument(llvm::makeArrayRef(Args, NumArgs)); } } llvm_unreachable("Unhandled template argument kind!"); } TemplateParameterList * ASTReader::ReadTemplateParameterList(ModuleFile &F, const RecordData &Record, unsigned &Idx) { SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx); SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx); SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx); unsigned NumParams = Record[Idx++]; SmallVector Params; Params.reserve(NumParams); while (NumParams--) Params.push_back(ReadDeclAs(F, Record, Idx)); // TODO: Concepts TemplateParameterList* TemplateParams = TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr); return TemplateParams; } void ASTReader:: ReadTemplateArgumentList(SmallVectorImpl &TemplArgs, ModuleFile &F, const RecordData &Record, unsigned &Idx, bool Canonicalize) { unsigned NumTemplateArgs = Record[Idx++]; TemplArgs.reserve(NumTemplateArgs); while (NumTemplateArgs--) TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx, Canonicalize)); } /// \brief Read a UnresolvedSet structure. void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set, const RecordData &Record, unsigned &Idx) { unsigned NumDecls = Record[Idx++]; Set.reserve(Context, NumDecls); while (NumDecls--) { DeclID ID = ReadDeclID(F, Record, Idx); AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; Set.addLazyDecl(Context, ID, AS); } } CXXBaseSpecifier ASTReader::ReadCXXBaseSpecifier(ModuleFile &F, const RecordData &Record, unsigned &Idx) { bool isVirtual = static_cast(Record[Idx++]); bool isBaseOfClass = static_cast(Record[Idx++]); AccessSpecifier AS = static_cast(Record[Idx++]); bool inheritConstructors = static_cast(Record[Idx++]); TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx); CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo, EllipsisLoc); Result.setInheritConstructors(inheritConstructors); return Result; } CXXCtorInitializer ** ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, unsigned &Idx) { unsigned NumInitializers = Record[Idx++]; assert(NumInitializers && "wrote ctor initializers but have no inits"); auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; for (unsigned i = 0; i != NumInitializers; ++i) { TypeSourceInfo *TInfo = nullptr; bool IsBaseVirtual = false; FieldDecl *Member = nullptr; IndirectFieldDecl *IndirectMember = nullptr; CtorInitializerType Type = (CtorInitializerType)Record[Idx++]; switch (Type) { case CTOR_INITIALIZER_BASE: TInfo = GetTypeSourceInfo(F, Record, Idx); IsBaseVirtual = Record[Idx++]; break; case CTOR_INITIALIZER_DELEGATING: TInfo = GetTypeSourceInfo(F, Record, Idx); break; case CTOR_INITIALIZER_MEMBER: Member = ReadDeclAs(F, Record, Idx); break; case CTOR_INITIALIZER_INDIRECT_MEMBER: IndirectMember = ReadDeclAs(F, Record, Idx); break; } SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx); Expr *Init = ReadExpr(F); SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx); SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx); CXXCtorInitializer *BOMInit; if (Type == CTOR_INITIALIZER_BASE) BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual, LParenLoc, Init, RParenLoc, MemberOrEllipsisLoc); else if (Type == CTOR_INITIALIZER_DELEGATING) BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc, Init, RParenLoc); else if (Member) BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); else BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); if (/*IsWritten*/Record[Idx++]) { unsigned SourceOrder = Record[Idx++]; BOMInit->setSourceOrder(SourceOrder); } CtorInitializers[i] = BOMInit; } return CtorInitializers; } NestedNameSpecifier * ASTReader::ReadNestedNameSpecifier(ModuleFile &F, const RecordData &Record, unsigned &Idx) { unsigned N = Record[Idx++]; NestedNameSpecifier *NNS = nullptr, *Prev = nullptr; for (unsigned I = 0; I != N; ++I) { NestedNameSpecifier::SpecifierKind Kind = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; switch (Kind) { case NestedNameSpecifier::Identifier: { IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); NNS = NestedNameSpecifier::Create(Context, Prev, II); break; } case NestedNameSpecifier::Namespace: { NamespaceDecl *NS = ReadDeclAs(F, Record, Idx); NNS = NestedNameSpecifier::Create(Context, Prev, NS); break; } case NestedNameSpecifier::NamespaceAlias: { NamespaceAliasDecl *Alias =ReadDeclAs(F, Record, Idx); NNS = NestedNameSpecifier::Create(Context, Prev, Alias); break; } case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { const Type *T = readType(F, Record, Idx).getTypePtrOrNull(); if (!T) return nullptr; bool Template = Record[Idx++]; NNS = NestedNameSpecifier::Create(Context, Prev, Template, T); break; } case NestedNameSpecifier::Global: { NNS = NestedNameSpecifier::GlobalSpecifier(Context); // No associated value, and there can't be a prefix. break; } case NestedNameSpecifier::Super: { CXXRecordDecl *RD = ReadDeclAs(F, Record, Idx); NNS = NestedNameSpecifier::SuperSpecifier(Context, RD); break; } } Prev = NNS; } return NNS; } NestedNameSpecifierLoc ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record, unsigned &Idx) { unsigned N = Record[Idx++]; NestedNameSpecifierLocBuilder Builder; for (unsigned I = 0; I != N; ++I) { NestedNameSpecifier::SpecifierKind Kind = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; switch (Kind) { case NestedNameSpecifier::Identifier: { IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); Builder.Extend(Context, II, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::Namespace: { NamespaceDecl *NS = ReadDeclAs(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::NamespaceAlias: { NamespaceAliasDecl *Alias =ReadDeclAs(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { bool Template = Record[Idx++]; TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx); if (!T) return NestedNameSpecifierLoc(); SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); // FIXME: 'template' keyword location not saved anywhere, so we fake it. Builder.Extend(Context, Template? T->getTypeLoc().getBeginLoc() : SourceLocation(), T->getTypeLoc(), ColonColonLoc); break; } case NestedNameSpecifier::Global: { SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); Builder.MakeGlobal(Context, ColonColonLoc); break; } case NestedNameSpecifier::Super: { CXXRecordDecl *RD = ReadDeclAs(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); Builder.MakeSuper(Context, RD, Range.getBegin(), Range.getEnd()); break; } } } return Builder.getWithLocInContext(Context); } SourceRange ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record, unsigned &Idx) { SourceLocation beg = ReadSourceLocation(F, Record, Idx); SourceLocation end = ReadSourceLocation(F, Record, Idx); return SourceRange(beg, end); } /// \brief Read an integral value llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) { unsigned BitWidth = Record[Idx++]; unsigned NumWords = llvm::APInt::getNumWords(BitWidth); llvm::APInt Result(BitWidth, NumWords, &Record[Idx]); Idx += NumWords; return Result; } /// \brief Read a signed integral value llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) { bool isUnsigned = Record[Idx++]; return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned); } /// \brief Read a floating-point value llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, const llvm::fltSemantics &Sem, unsigned &Idx) { return llvm::APFloat(Sem, ReadAPInt(Record, Idx)); } // \brief Read a string std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) { unsigned Len = Record[Idx++]; std::string Result(Record.data() + Idx, Record.data() + Idx + Len); Idx += Len; return Result; } std::string ASTReader::ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx) { std::string Filename = ReadString(Record, Idx); ResolveImportedPath(F, Filename); return Filename; } VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record, unsigned &Idx) { unsigned Major = Record[Idx++]; unsigned Minor = Record[Idx++]; unsigned Subminor = Record[Idx++]; if (Minor == 0) return VersionTuple(Major); if (Subminor == 0) return VersionTuple(Major, Minor - 1); return VersionTuple(Major, Minor - 1, Subminor - 1); } CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F, const RecordData &Record, unsigned &Idx) { CXXDestructorDecl *Decl = ReadDeclAs(F, Record, Idx); return CXXTemporary::Create(Context, Decl); } DiagnosticBuilder ASTReader::Diag(unsigned DiagID) const { return Diag(CurrentImportLoc, DiagID); } DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) const { return Diags.Report(Loc, DiagID); } /// \brief Retrieve the identifier table associated with the /// preprocessor. IdentifierTable &ASTReader::getIdentifierTable() { return PP.getIdentifierTable(); } /// \brief Record that the given ID maps to the given switch-case /// statement. void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) { assert((*CurrSwitchCaseStmts)[ID] == nullptr && "Already have a SwitchCase with this ID"); (*CurrSwitchCaseStmts)[ID] = SC; } /// \brief Retrieve the switch-case statement with the given ID. SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) { assert((*CurrSwitchCaseStmts)[ID] != nullptr && "No SwitchCase with this ID"); return (*CurrSwitchCaseStmts)[ID]; } void ASTReader::ClearSwitchCaseIDs() { CurrSwitchCaseStmts->clear(); } void ASTReader::ReadComments() { std::vector Comments; for (SmallVectorImpl >::iterator I = CommentsCursors.begin(), E = CommentsCursors.end(); I != E; ++I) { Comments.clear(); BitstreamCursor &Cursor = I->first; serialization::ModuleFile &F = *I->second; SavedStreamPosition SavedPosition(Cursor); RecordData Record; while (true) { llvm::BitstreamEntry Entry = Cursor.advanceSkippingSubblocks(BitstreamCursor::AF_DontPopBlockAtEnd); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return; case llvm::BitstreamEntry::EndBlock: goto NextCursor; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); switch ((CommentRecordTypes)Cursor.readRecord(Entry.ID, Record)) { case COMMENTS_RAW_COMMENT: { unsigned Idx = 0; SourceRange SR = ReadSourceRange(F, Record, Idx); RawComment::CommentKind Kind = (RawComment::CommentKind) Record[Idx++]; bool IsTrailingComment = Record[Idx++]; bool IsAlmostTrailingComment = Record[Idx++]; Comments.push_back(new (Context) RawComment( SR, Kind, IsTrailingComment, IsAlmostTrailingComment, Context.getLangOpts().CommentOpts.ParseAllComments)); break; } } } NextCursor: // De-serialized SourceLocations get negative FileIDs for other modules, // potentially invalidating the original order. Sort it again. std::sort(Comments.begin(), Comments.end(), BeforeThanCompare(SourceMgr)); Context.Comments.addDeserializedComments(Comments); } } void ASTReader::visitInputFiles(serialization::ModuleFile &MF, bool IncludeSystem, bool Complain, llvm::function_ref Visitor) { unsigned NumUserInputs = MF.NumUserInputFiles; unsigned NumInputs = MF.InputFilesLoaded.size(); assert(NumUserInputs <= NumInputs); unsigned N = IncludeSystem ? NumInputs : NumUserInputs; for (unsigned I = 0; I < N; ++I) { bool IsSystem = I >= NumUserInputs; InputFile IF = getInputFile(MF, I+1, Complain); Visitor(IF, IsSystem); } } std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { // If we know the owning module, use it. if (Module *M = D->getImportedOwningModule()) return M->getFullModuleName(); // Otherwise, use the name of the top-level module the decl is within. if (ModuleFile *M = getOwningModuleFile(D)) return M->ModuleName; // Not from a module. return ""; } void ASTReader::finishPendingActions() { while (!PendingIdentifierInfos.empty() || !PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() || !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() || !PendingUpdateRecords.empty()) { // If any identifiers with corresponding top-level declarations have // been loaded, load those declarations now. typedef llvm::DenseMap > TopLevelDeclsMap; TopLevelDeclsMap TopLevelDecls; while (!PendingIdentifierInfos.empty()) { IdentifierInfo *II = PendingIdentifierInfos.back().first; SmallVector DeclIDs = std::move(PendingIdentifierInfos.back().second); PendingIdentifierInfos.pop_back(); SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]); } // For each decl chain that we wanted to complete while deserializing, mark // it as "still needs to be completed". for (unsigned I = 0; I != PendingIncompleteDeclChains.size(); ++I) { markIncompleteDeclChain(PendingIncompleteDeclChains[I]); } PendingIncompleteDeclChains.clear(); // Load pending declaration chains. for (unsigned I = 0; I != PendingDeclChains.size(); ++I) loadPendingDeclChain(PendingDeclChains[I].first, PendingDeclChains[I].second); PendingDeclChains.clear(); // Make the most recent of the top-level declarations visible. for (TopLevelDeclsMap::iterator TLD = TopLevelDecls.begin(), TLDEnd = TopLevelDecls.end(); TLD != TLDEnd; ++TLD) { IdentifierInfo *II = TLD->first; for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) { pushExternalDeclIntoScope(cast(TLD->second[I]), II); } } // Load any pending macro definitions. for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) { IdentifierInfo *II = PendingMacroIDs.begin()[I].first; SmallVector GlobalIDs; GlobalIDs.swap(PendingMacroIDs.begin()[I].second); // Initialize the macro history from chained-PCHs ahead of module imports. for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; ++IDIdx) { const PendingMacroInfo &Info = GlobalIDs[IDIdx]; if (!Info.M->isModule()) resolvePendingMacro(II, Info); } // Handle module imports. for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; ++IDIdx) { const PendingMacroInfo &Info = GlobalIDs[IDIdx]; if (Info.M->isModule()) resolvePendingMacro(II, Info); } } PendingMacroIDs.clear(); // Wire up the DeclContexts for Decls that we delayed setting until // recursive loading is completed. while (!PendingDeclContextInfos.empty()) { PendingDeclContextInfo Info = PendingDeclContextInfos.front(); PendingDeclContextInfos.pop_front(); DeclContext *SemaDC = cast(GetDecl(Info.SemaDC)); DeclContext *LexicalDC = cast(GetDecl(Info.LexicalDC)); Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext()); } // Perform any pending declaration updates. while (!PendingUpdateRecords.empty()) { auto Update = PendingUpdateRecords.pop_back_val(); ReadingKindTracker ReadingKind(Read_Decl, *this); loadDeclUpdateRecords(Update.first, Update.second); } } // At this point, all update records for loaded decls are in place, so any // fake class definitions should have become real. assert(PendingFakeDefinitionData.empty() && "faked up a class definition but never saw the real one"); // If we deserialized any C++ or Objective-C class definitions, any // Objective-C protocol definitions, or any redeclarable templates, make sure // that all redeclarations point to the definitions. Note that this can only // happen now, after the redeclaration chains have been fully wired. for (Decl *D : PendingDefinitions) { if (TagDecl *TD = dyn_cast(D)) { if (const TagType *TagT = dyn_cast(TD->getTypeForDecl())) { // Make sure that the TagType points at the definition. const_cast(TagT)->decl = TD; } if (auto RD = dyn_cast(D)) { for (auto *R = getMostRecentExistingDecl(RD); R; R = R->getPreviousDecl()) { assert((R == D) == cast(R)->isThisDeclarationADefinition() && "declaration thinks it's the definition but it isn't"); cast(R)->DefinitionData = RD->DefinitionData; } } continue; } if (auto ID = dyn_cast(D)) { // Make sure that the ObjCInterfaceType points at the definition. const_cast(cast(ID->TypeForDecl)) ->Decl = ID; for (auto *R = getMostRecentExistingDecl(ID); R; R = R->getPreviousDecl()) cast(R)->Data = ID->Data; continue; } if (auto PD = dyn_cast(D)) { for (auto *R = getMostRecentExistingDecl(PD); R; R = R->getPreviousDecl()) cast(R)->Data = PD->Data; continue; } auto RTD = cast(D)->getCanonicalDecl(); for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl()) cast(R)->Common = RTD->Common; } PendingDefinitions.clear(); // Load the bodies of any functions or methods we've encountered. We do // this now (delayed) so that we can be sure that the declaration chains // have been fully wired up (hasBody relies on this). // FIXME: We shouldn't require complete redeclaration chains here. for (PendingBodiesMap::iterator PB = PendingBodies.begin(), PBEnd = PendingBodies.end(); PB != PBEnd; ++PB) { if (FunctionDecl *FD = dyn_cast(PB->first)) { // FIXME: Check for =delete/=default? // FIXME: Complain about ODR violations here? const FunctionDecl *Defn = nullptr; if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) { FD->setLazyBody(PB->second); } else mergeDefinitionVisibility(const_cast(Defn), FD); continue; } ObjCMethodDecl *MD = cast(PB->first); if (!getContext().getLangOpts().Modules || !MD->hasBody()) MD->setLazyBody(PB->second); } PendingBodies.clear(); // Do some cleanup. for (auto *ND : PendingMergedDefinitionsToDeduplicate) getContext().deduplicateMergedDefinitonsFor(ND); PendingMergedDefinitionsToDeduplicate.clear(); } void ASTReader::diagnoseOdrViolations() { if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty()) return; // Trigger the import of the full definition of each class that had any // odr-merging problems, so we can produce better diagnostics for them. // These updates may in turn find and diagnose some ODR failures, so take // ownership of the set first. auto OdrMergeFailures = std::move(PendingOdrMergeFailures); PendingOdrMergeFailures.clear(); for (auto &Merge : OdrMergeFailures) { Merge.first->buildLookup(); Merge.first->decls_begin(); Merge.first->bases_begin(); Merge.first->vbases_begin(); for (auto *RD : Merge.second) { RD->decls_begin(); RD->bases_begin(); RD->vbases_begin(); } } // For each declaration from a merged context, check that the canonical // definition of that context also contains a declaration of the same // entity. // // Caution: this loop does things that might invalidate iterators into // PendingOdrMergeChecks. Don't turn this into a range-based for loop! while (!PendingOdrMergeChecks.empty()) { NamedDecl *D = PendingOdrMergeChecks.pop_back_val(); // FIXME: Skip over implicit declarations for now. This matters for things // like implicitly-declared special member functions. This isn't entirely // correct; we can end up with multiple unmerged declarations of the same // implicit entity. if (D->isImplicit()) continue; DeclContext *CanonDef = D->getDeclContext(); bool Found = false; const Decl *DCanon = D->getCanonicalDecl(); for (auto RI : D->redecls()) { if (RI->getLexicalDeclContext() == CanonDef) { Found = true; break; } } if (Found) continue; // Quick check failed, time to do the slow thing. Note, we can't just // look up the name of D in CanonDef here, because the member that is // in CanonDef might not be found by name lookup (it might have been // replaced by a more recent declaration in the lookup table), and we // can't necessarily find it in the redeclaration chain because it might // be merely mergeable, not redeclarable. llvm::SmallVector Candidates; for (auto *CanonMember : CanonDef->decls()) { if (CanonMember->getCanonicalDecl() == DCanon) { // This can happen if the declaration is merely mergeable and not // actually redeclarable (we looked for redeclarations earlier). // // FIXME: We should be able to detect this more efficiently, without // pulling in all of the members of CanonDef. Found = true; break; } if (auto *ND = dyn_cast(CanonMember)) if (ND->getDeclName() == D->getDeclName()) Candidates.push_back(ND); } if (!Found) { // The AST doesn't like TagDecls becoming invalid after they've been // completed. We only really need to mark FieldDecls as invalid here. if (!isa(D)) D->setInvalidDecl(); // Ensure we don't accidentally recursively enter deserialization while // we're producing our diagnostic. Deserializing RecursionGuard(this); std::string CanonDefModule = getOwningModuleNameForDiagnostic(cast(CanonDef)); Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl) << D << getOwningModuleNameForDiagnostic(D) << CanonDef << CanonDefModule.empty() << CanonDefModule; if (Candidates.empty()) Diag(cast(CanonDef)->getLocation(), diag::note_module_odr_violation_no_possible_decls) << D; else { for (unsigned I = 0, N = Candidates.size(); I != N; ++I) Diag(Candidates[I]->getLocation(), diag::note_module_odr_violation_possible_decl) << Candidates[I]; } DiagnosedOdrMergeFailures.insert(CanonDef); } } if (OdrMergeFailures.empty()) return; // Ensure we don't accidentally recursively enter deserialization while // we're producing our diagnostics. Deserializing RecursionGuard(this); // Issue any pending ODR-failure diagnostics. for (auto &Merge : OdrMergeFailures) { // If we've already pointed out a specific problem with this class, don't // bother issuing a general "something's different" diagnostic. if (!DiagnosedOdrMergeFailures.insert(Merge.first).second) continue; bool Diagnosed = false; CXXRecordDecl *FirstRecord = Merge.first; std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord); for (CXXRecordDecl *SecondRecord : Merge.second) { // Multiple different declarations got merged together; tell the user // where they came from. if (FirstRecord == SecondRecord) continue; std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord); using DeclHashes = llvm::SmallVector, 4>; DeclHashes FirstHashes; DeclHashes SecondHashes; ODRHash Hash; auto PopulateHashes = [&Hash, FirstRecord](DeclHashes &Hashes, CXXRecordDecl *Record) { for (auto *D : Record->decls()) { // Due to decl merging, the first CXXRecordDecl is the parent of // Decls in both records. if (!ODRHash::isWhitelistedDecl(D, FirstRecord)) continue; Hash.clear(); Hash.AddSubDecl(D); Hashes.emplace_back(D, Hash.CalculateHash()); } }; PopulateHashes(FirstHashes, FirstRecord); PopulateHashes(SecondHashes, SecondRecord); // Used with err_module_odr_violation_mismatch_decl and // note_module_odr_violation_mismatch_decl enum { EndOfClass, PublicSpecifer, PrivateSpecifer, ProtectedSpecifer, StaticAssert, Field, CXXMethod, Other } FirstDiffType = Other, SecondDiffType = Other; auto DifferenceSelector = [](Decl *D) { assert(D && "valid Decl required"); switch (D->getKind()) { default: return Other; case Decl::AccessSpec: switch (D->getAccess()) { case AS_public: return PublicSpecifer; case AS_private: return PrivateSpecifer; case AS_protected: return ProtectedSpecifer; case AS_none: break; } llvm_unreachable("Invalid access specifier"); case Decl::StaticAssert: return StaticAssert; case Decl::Field: return Field; case Decl::CXXMethod: return CXXMethod; } }; Decl *FirstDecl = nullptr; Decl *SecondDecl = nullptr; auto FirstIt = FirstHashes.begin(); auto SecondIt = SecondHashes.begin(); // If there is a diagnoseable difference, FirstDiffType and // SecondDiffType will not be Other and FirstDecl and SecondDecl will be // filled in if not EndOfClass. while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) { if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() && FirstIt->second == SecondIt->second) { ++FirstIt; ++SecondIt; continue; } FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first; SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first; FirstDiffType = FirstDecl ? DifferenceSelector(FirstDecl) : EndOfClass; SecondDiffType = SecondDecl ? DifferenceSelector(SecondDecl) : EndOfClass; break; } if (FirstDiffType == Other || SecondDiffType == Other) { // Reaching this point means an unexpected Decl was encountered // or no difference was detected. This causes a generic error // message to be emitted. Diag(FirstRecord->getLocation(), diag::err_module_odr_violation_different_definitions) << FirstRecord << FirstModule.empty() << FirstModule; Diag(SecondRecord->getLocation(), diag::note_module_odr_violation_different_definitions) << SecondModule; Diagnosed = true; break; } if (FirstDiffType != SecondDiffType) { SourceLocation FirstLoc; SourceRange FirstRange; if (FirstDiffType == EndOfClass) { FirstLoc = FirstRecord->getBraceRange().getEnd(); } else { FirstLoc = FirstIt->first->getLocation(); FirstRange = FirstIt->first->getSourceRange(); } Diag(FirstLoc, diag::err_module_odr_violation_mismatch_decl) << FirstRecord << FirstModule.empty() << FirstModule << FirstRange << FirstDiffType; SourceLocation SecondLoc; SourceRange SecondRange; if (SecondDiffType == EndOfClass) { SecondLoc = SecondRecord->getBraceRange().getEnd(); } else { SecondLoc = SecondDecl->getLocation(); SecondRange = SecondDecl->getSourceRange(); } Diag(SecondLoc, diag::note_module_odr_violation_mismatch_decl) << SecondModule << SecondRange << SecondDiffType; Diagnosed = true; break; } assert(FirstDiffType == SecondDiffType); // Used with err_module_odr_violation_mismatch_decl_diff and // note_module_odr_violation_mismatch_decl_diff enum ODRDeclDifference{ StaticAssertCondition, StaticAssertMessage, StaticAssertOnlyMessage, FieldName, FieldTypeName, FieldSingleBitField, FieldDifferentWidthBitField, FieldSingleMutable, FieldSingleInitializer, FieldDifferentInitializers, MethodName, MethodDeleted, MethodVirtual, MethodStatic, MethodVolatile, MethodConst, MethodInline, MethodNumberParameters, MethodParameterType, MethodParameterName, }; // These lambdas have the common portions of the ODR diagnostics. This // has the same return as Diag(), so addition parameters can be passed // in with operator<< auto ODRDiagError = [FirstRecord, &FirstModule, this]( SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) { return Diag(Loc, diag::err_module_odr_violation_mismatch_decl_diff) << FirstRecord << FirstModule.empty() << FirstModule << Range << DiffType; }; auto ODRDiagNote = [&SecondModule, this]( SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) { return Diag(Loc, diag::note_module_odr_violation_mismatch_decl_diff) << SecondModule << Range << DiffType; }; auto ComputeODRHash = [&Hash](const Stmt* S) { assert(S); Hash.clear(); Hash.AddStmt(S); return Hash.CalculateHash(); }; - auto ComputeDeclNameODRHash = [&Hash](const DeclarationName Name) { - Hash.clear(); - Hash.AddDeclarationName(Name); - return Hash.CalculateHash(); - }; - auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { Hash.clear(); Hash.AddQualType(Ty); return Hash.CalculateHash(); }; switch (FirstDiffType) { case Other: case EndOfClass: case PublicSpecifer: case PrivateSpecifer: case ProtectedSpecifer: llvm_unreachable("Invalid diff type"); case StaticAssert: { StaticAssertDecl *FirstSA = cast(FirstDecl); StaticAssertDecl *SecondSA = cast(SecondDecl); Expr *FirstExpr = FirstSA->getAssertExpr(); Expr *SecondExpr = SecondSA->getAssertExpr(); unsigned FirstODRHash = ComputeODRHash(FirstExpr); unsigned SecondODRHash = ComputeODRHash(SecondExpr); if (FirstODRHash != SecondODRHash) { ODRDiagError(FirstExpr->getLocStart(), FirstExpr->getSourceRange(), StaticAssertCondition); ODRDiagNote(SecondExpr->getLocStart(), SecondExpr->getSourceRange(), StaticAssertCondition); Diagnosed = true; break; } StringLiteral *FirstStr = FirstSA->getMessage(); StringLiteral *SecondStr = SecondSA->getMessage(); assert((FirstStr || SecondStr) && "Both messages cannot be empty"); if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) { SourceLocation FirstLoc, SecondLoc; SourceRange FirstRange, SecondRange; if (FirstStr) { FirstLoc = FirstStr->getLocStart(); FirstRange = FirstStr->getSourceRange(); } else { FirstLoc = FirstSA->getLocStart(); FirstRange = FirstSA->getSourceRange(); } if (SecondStr) { SecondLoc = SecondStr->getLocStart(); SecondRange = SecondStr->getSourceRange(); } else { SecondLoc = SecondSA->getLocStart(); SecondRange = SecondSA->getSourceRange(); } ODRDiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage) << (FirstStr == nullptr); ODRDiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage) << (SecondStr == nullptr); Diagnosed = true; break; } if (FirstStr && SecondStr && FirstStr->getString() != SecondStr->getString()) { ODRDiagError(FirstStr->getLocStart(), FirstStr->getSourceRange(), StaticAssertMessage); ODRDiagNote(SecondStr->getLocStart(), SecondStr->getSourceRange(), StaticAssertMessage); Diagnosed = true; break; } break; } case Field: { FieldDecl *FirstField = cast(FirstDecl); FieldDecl *SecondField = cast(SecondDecl); IdentifierInfo *FirstII = FirstField->getIdentifier(); IdentifierInfo *SecondII = SecondField->getIdentifier(); if (FirstII->getName() != SecondII->getName()) { ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), FieldName) << FirstII; ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), FieldName) << SecondII; Diagnosed = true; break; } assert( Context.hasSameType(FirstField->getType(), SecondField->getType())); QualType FirstType = FirstField->getType(); QualType SecondType = SecondField->getType(); - const TypedefType *FirstTypedef = dyn_cast(FirstType); - const TypedefType *SecondTypedef = dyn_cast(SecondType); - - if ((FirstTypedef && !SecondTypedef) || - (!FirstTypedef && SecondTypedef)) { + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), FieldTypeName) << FirstII << FirstType; ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), FieldTypeName) << SecondII << SecondType; Diagnosed = true; break; - } - - if (FirstTypedef && SecondTypedef) { - unsigned FirstHash = ComputeDeclNameODRHash( - FirstTypedef->getDecl()->getDeclName()); - unsigned SecondHash = ComputeDeclNameODRHash( - SecondTypedef->getDecl()->getDeclName()); - if (FirstHash != SecondHash) { - ODRDiagError(FirstField->getLocation(), - FirstField->getSourceRange(), FieldTypeName) - << FirstII << FirstType; - ODRDiagNote(SecondField->getLocation(), - SecondField->getSourceRange(), FieldTypeName) - << SecondII << SecondType; - - Diagnosed = true; - break; - } } const bool IsFirstBitField = FirstField->isBitField(); const bool IsSecondBitField = SecondField->isBitField(); if (IsFirstBitField != IsSecondBitField) { ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), FieldSingleBitField) << FirstII << IsFirstBitField; ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), FieldSingleBitField) << SecondII << IsSecondBitField; Diagnosed = true; break; } if (IsFirstBitField && IsSecondBitField) { ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), FieldDifferentWidthBitField) << FirstII << FirstField->getBitWidth()->getSourceRange(); ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), FieldDifferentWidthBitField) << SecondII << SecondField->getBitWidth()->getSourceRange(); Diagnosed = true; break; } const bool IsFirstMutable = FirstField->isMutable(); const bool IsSecondMutable = SecondField->isMutable(); if (IsFirstMutable != IsSecondMutable) { ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), FieldSingleMutable) << FirstII << IsFirstMutable; ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), FieldSingleMutable) << SecondII << IsSecondMutable; Diagnosed = true; break; } const Expr *FirstInitializer = FirstField->getInClassInitializer(); const Expr *SecondInitializer = SecondField->getInClassInitializer(); if ((!FirstInitializer && SecondInitializer) || (FirstInitializer && !SecondInitializer)) { ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), FieldSingleInitializer) << FirstII << (FirstInitializer != nullptr); ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), FieldSingleInitializer) << SecondII << (SecondInitializer != nullptr); Diagnosed = true; break; } if (FirstInitializer && SecondInitializer) { unsigned FirstInitHash = ComputeODRHash(FirstInitializer); unsigned SecondInitHash = ComputeODRHash(SecondInitializer); if (FirstInitHash != SecondInitHash) { ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), FieldDifferentInitializers) << FirstII << FirstInitializer->getSourceRange(); ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), FieldDifferentInitializers) << SecondII << SecondInitializer->getSourceRange(); Diagnosed = true; break; } } break; } case CXXMethod: { const CXXMethodDecl *FirstMethod = cast(FirstDecl); const CXXMethodDecl *SecondMethod = cast(SecondDecl); auto FirstName = FirstMethod->getDeclName(); auto SecondName = SecondMethod->getDeclName(); if (FirstName != SecondName) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodName) << FirstName; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodName) << SecondName; Diagnosed = true; break; } const bool FirstDeleted = FirstMethod->isDeleted(); const bool SecondDeleted = SecondMethod->isDeleted(); if (FirstDeleted != SecondDeleted) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodDeleted) << FirstName << FirstDeleted; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodDeleted) << SecondName << SecondDeleted; Diagnosed = true; break; } const bool FirstVirtual = FirstMethod->isVirtualAsWritten(); const bool SecondVirtual = SecondMethod->isVirtualAsWritten(); const bool FirstPure = FirstMethod->isPure(); const bool SecondPure = SecondMethod->isPure(); if ((FirstVirtual || SecondVirtual) && (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodVirtual) << FirstName << FirstPure << FirstVirtual; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodVirtual) << SecondName << SecondPure << SecondVirtual; Diagnosed = true; break; } // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging, // FirstDecl is the canonical Decl of SecondDecl, so the storage // class needs to be checked instead. const auto FirstStorage = FirstMethod->getStorageClass(); const auto SecondStorage = SecondMethod->getStorageClass(); const bool FirstStatic = FirstStorage == SC_Static; const bool SecondStatic = SecondStorage == SC_Static; if (FirstStatic != SecondStatic) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodStatic) << FirstName << FirstStatic; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodStatic) << SecondName << SecondStatic; Diagnosed = true; break; } const bool FirstVolatile = FirstMethod->isVolatile(); const bool SecondVolatile = SecondMethod->isVolatile(); if (FirstVolatile != SecondVolatile) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodVolatile) << FirstName << FirstVolatile; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodVolatile) << SecondName << SecondVolatile; Diagnosed = true; break; } const bool FirstConst = FirstMethod->isConst(); const bool SecondConst = SecondMethod->isConst(); if (FirstConst != SecondConst) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodConst) << FirstName << FirstConst; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodConst) << SecondName << SecondConst; Diagnosed = true; break; } const bool FirstInline = FirstMethod->isInlineSpecified(); const bool SecondInline = SecondMethod->isInlineSpecified(); if (FirstInline != SecondInline) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodInline) << FirstName << FirstInline; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodInline) << SecondName << SecondInline; Diagnosed = true; break; } const unsigned FirstNumParameters = FirstMethod->param_size(); const unsigned SecondNumParameters = SecondMethod->param_size(); if (FirstNumParameters != SecondNumParameters) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodNumberParameters) << FirstName << FirstNumParameters; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodNumberParameters) << SecondName << SecondNumParameters; Diagnosed = true; break; } // Need this status boolean to know when break out of the switch. bool ParameterMismatch = false; for (unsigned I = 0; I < FirstNumParameters; ++I) { const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I); const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I); QualType FirstParamType = FirstParam->getType(); QualType SecondParamType = SecondParam->getType(); if (FirstParamType != SecondParamType && ComputeQualTypeODRHash(FirstParamType) != ComputeQualTypeODRHash(SecondParamType)) { if (const DecayedType *ParamDecayedType = FirstParamType->getAs()) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodParameterType) << FirstName << (I + 1) << FirstParamType << true << ParamDecayedType->getOriginalType(); } else { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodParameterType) << FirstName << (I + 1) << FirstParamType << false; } if (const DecayedType *ParamDecayedType = SecondParamType->getAs()) { ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodParameterType) << SecondName << (I + 1) << SecondParamType << true << ParamDecayedType->getOriginalType(); } else { ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodParameterType) << SecondName << (I + 1) << SecondParamType << false; } ParameterMismatch = true; break; } DeclarationName FirstParamName = FirstParam->getDeclName(); DeclarationName SecondParamName = SecondParam->getDeclName(); if (FirstParamName != SecondParamName) { ODRDiagError(FirstMethod->getLocation(), FirstMethod->getSourceRange(), MethodParameterName) << FirstName << (I + 1) << FirstParamName; ODRDiagNote(SecondMethod->getLocation(), SecondMethod->getSourceRange(), MethodParameterName) << SecondName << (I + 1) << SecondParamName; ParameterMismatch = true; break; } } if (ParameterMismatch) { Diagnosed = true; break; } break; } } if (Diagnosed == true) continue; Diag(FirstRecord->getLocation(), diag::err_module_odr_violation_different_definitions) << FirstRecord << FirstModule.empty() << FirstModule; Diag(SecondRecord->getLocation(), diag::note_module_odr_violation_different_definitions) << SecondModule; Diagnosed = true; } if (!Diagnosed) { // All definitions are updates to the same declaration. This happens if a // module instantiates the declaration of a class template specialization // and two or more other modules instantiate its definition. // // FIXME: Indicate which modules had instantiations of this definition. // FIXME: How can this even happen? Diag(Merge.first->getLocation(), diag::err_module_odr_violation_different_instantiations) << Merge.first; } } } void ASTReader::StartedDeserializing() { if (++NumCurrentElementsDeserializing == 1 && ReadTimer.get()) ReadTimer->startTimer(); } void ASTReader::FinishedDeserializing() { assert(NumCurrentElementsDeserializing && "FinishedDeserializing not paired with StartedDeserializing"); if (NumCurrentElementsDeserializing == 1) { // We decrease NumCurrentElementsDeserializing only after pending actions // are finished, to avoid recursively re-calling finishPendingActions(). finishPendingActions(); } --NumCurrentElementsDeserializing; if (NumCurrentElementsDeserializing == 0) { // Propagate exception specification updates along redeclaration chains. while (!PendingExceptionSpecUpdates.empty()) { auto Updates = std::move(PendingExceptionSpecUpdates); PendingExceptionSpecUpdates.clear(); for (auto Update : Updates) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); auto *FPT = Update.second->getType()->castAs(); auto ESI = FPT->getExtProtoInfo().ExceptionSpec; if (auto *Listener = Context.getASTMutationListener()) Listener->ResolvedExceptionSpec(cast(Update.second)); for (auto *Redecl : Update.second->redecls()) Context.adjustExceptionSpec(cast(Redecl), ESI); } } if (ReadTimer) ReadTimer->stopTimer(); diagnoseOdrViolations(); // We are not in recursive loading, so it's safe to pass the "interesting" // decls to the consumer. if (Consumer) PassInterestingDeclsToConsumer(); } } void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { if (IdentifierInfo *II = Name.getAsIdentifierInfo()) { // Remove any fake results before adding any real ones. auto It = PendingFakeLookupResults.find(II); if (It != PendingFakeLookupResults.end()) { for (auto *ND : It->second) SemaObj->IdResolver.RemoveDecl(ND); // FIXME: this works around module+PCH performance issue. // Rather than erase the result from the map, which is O(n), just clear // the vector of NamedDecls. It->second.clear(); } } if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) { SemaObj->TUScope->AddDecl(D); } else if (SemaObj->TUScope) { // Adding the decl to IdResolver may have failed because it was already in // (even though it was not added in scope). If it is already in, make sure // it gets in the scope as well. if (std::find(SemaObj->IdResolver.begin(Name), SemaObj->IdResolver.end(), D) != SemaObj->IdResolver.end()) SemaObj->TUScope->AddDecl(D); } } ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, const PCHContainerReader &PCHContainerRdr, ArrayRef> Extensions, StringRef isysroot, bool DisableValidation, bool AllowASTWithCompilerErrors, bool AllowConfigurationMismatch, bool ValidateSystemInputs, bool UseGlobalIndex, std::unique_ptr ReadTimer) : Listener(DisableValidation ? cast(new SimpleASTReaderListener(PP)) : cast(new PCHValidator(PP, *this))), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP), Context(Context), ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr), PCMCache(PP.getPCMCache()), DummyIdResolver(PP), ReadTimer(std::move(ReadTimer)), isysroot(isysroot), DisableValidation(DisableValidation), AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), AllowConfigurationMismatch(AllowConfigurationMismatch), ValidateSystemInputs(ValidateSystemInputs), UseGlobalIndex(UseGlobalIndex), CurrSwitchCaseStmts(&SwitchCaseStmts) { SourceMgr.setExternalSLocEntrySource(this); for (const auto &Ext : Extensions) { auto BlockName = Ext->getExtensionMetadata().BlockName; auto Known = ModuleFileExtensions.find(BlockName); if (Known != ModuleFileExtensions.end()) { Diags.Report(diag::warn_duplicate_module_file_extension) << BlockName; continue; } ModuleFileExtensions.insert({BlockName, Ext}); } } ASTReader::~ASTReader() { if (OwnsDeserializationListener) delete DeserializationListener; } IdentifierResolver &ASTReader::getIdResolver() { return SemaObj ? SemaObj->IdResolver : DummyIdResolver; } unsigned ASTRecordReader::readRecord(llvm::BitstreamCursor &Cursor, unsigned AbbrevID) { Idx = 0; Record.clear(); return Cursor.readRecord(AbbrevID, Record); } Index: vendor/clang/dist/test/CodeGenCXX/debug-info-namespace.cpp =================================================================== --- vendor/clang/dist/test/CodeGenCXX/debug-info-namespace.cpp (revision 318415) +++ vendor/clang/dist/test/CodeGenCXX/debug-info-namespace.cpp (revision 318416) @@ -1,124 +1,130 @@ // RUN: %clang_cc1 -std=c++11 -debug-info-kind=limited -S -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -std=c++11 -debug-info-kind=line-tables-only -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-GMLT %s // RUN: %clang_cc1 -std=c++11 -debug-info-kind=standalone -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-NOLIMIT %s namespace A { #line 1 "foo.cpp" namespace B { extern int i; int f1() { return 0; } void f1(int) { } struct foo; struct bar { }; typedef bar baz; extern int var_decl; void func_decl(void); extern int var_fwd; void func_fwd(void); } } namespace A { using namespace B; } using namespace A; namespace E = A; int B::i = f1(); int func(bool b) { if (b) { using namespace A::B; return i; } using namespace A; using B::foo; using B::bar; using B::f1; using B::i; using B::baz; namespace X = A; namespace Y = X; using B::var_decl; using B::func_decl; using B::var_fwd; using B::func_fwd; return i + X::B::i + Y::B::i; } namespace A { using B::i; namespace B { int var_fwd = i; } inline namespace I { int var_i; } } namespace { int anonymous; } void B::func_fwd() { anonymous = 0; } +namespace C { + void c(); +} +void C::c() {} // This should work even if 'i' and 'func' were declarations & not definitions, // but it doesn't yet. // CHECK: [[I:![0-9]+]] = distinct !DIGlobalVariable(name: "i",{{.*}} scope: [[NS:![0-9]+]], // CHECK: [[NS]] = !DINamespace(name: "B", scope: [[CTXT:![0-9]+]]) // CHECK: [[CTXT]] = !DINamespace(name: "A", scope: null) // CHECK: [[FOOCPP:.*]] = !DIFile(filename: "foo.cpp" // CHECK: [[VAR_FWD:![0-9]+]] = distinct !DIGlobalVariable(name: "var_fwd",{{.*}} scope: [[NS]], // CHECK-SAME: line: 44 // CHECK-SAME: isDefinition: true // CHECK: distinct !DIGlobalVariable(name: "var_i",{{.*}} scope: [[INLINE:![0-9]+]], // CHECK: [[INLINE]] = !DINamespace(name: "I", scope: [[CTXT]], exportSymbols: true) // CHECK: !DINamespace(scope: null) // CHECK: [[CU:![0-9]+]] = distinct !DICompileUnit( // CHECK-SAME: imports: [[MODULES:![0-9]*]] // CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]], [[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]] // CHECK: [[M1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CTXT]], entity: [[NS]], line: 15) // CHECK: [[M2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CU]], entity: [[CTXT]], // CHECK: [[M3]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "E", scope: [[CU]], entity: [[CTXT]], line: 19) // CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], line: 23) // CHECK: [[LEX2]] = distinct !DILexicalBlock(scope: [[LEX1:![0-9]+]], file: [[FOOCPP]], // CHECK: [[LEX1]] = distinct !DILexicalBlock(scope: [[FUNC:![0-9]+]], file: [[FOOCPP]], // CHECK: [[FUNC:![0-9]+]] = distinct !DISubprogram(name: "func",{{.*}} isDefinition: true // CHECK: [[M5]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[FUNC]], entity: [[CTXT:![0-9]+]], // CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], line: 27) // CHECK: [[FOO]] = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", // CHECK-SAME: line: 5 // CHECK-SAME: DIFlagFwdDecl // CHECK: [[M7]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAR:![0-9]+]] // CHECK: [[BAR]] = !DICompositeType(tag: DW_TAG_structure_type, name: "bar", // CHECK-SAME: line: 6 // CHECK-SAME: DIFlagFwdDecl // CHECK: [[M8]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[F1:![0-9]+]] // CHECK: [[F1:![0-9]+]] = distinct !DISubprogram(name: "f1",{{.*}} line: 4 // CHECK-SAME: isDefinition: true // CHECK: [[M9]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[I]] // CHECK: [[M10]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAZ:![0-9]+]] // CHECK: [[BAZ]] = !DIDerivedType(tag: DW_TAG_typedef, name: "baz", scope: [[NS]], file: [[FOOCPP]], // CHECK-SAME: baseType: [[BAR]] // CHECK: [[M11]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "X", scope: [[FUNC]], entity: [[CTXT]] // CHECK: [[M12]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "Y", scope: [[FUNC]], entity: [[M11]] // CHECK: [[M13]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_DECL:![0-9]+]] // CHECK: [[VAR_DECL]] = !DIGlobalVariable(name: "var_decl", linkageName: "{{[^"]*var_decl[^"]*}}", scope: [[NS]],{{.*}} line: 8, // CHECK: [[M14]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_DECL:![0-9]+]] // CHECK: [[FUNC_DECL]] = !DISubprogram(name: "func_decl", // CHECK-SAME: scope: [[NS]], file: [[FOOCPP]], line: 9 // CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]] // CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]] // CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 53,{{.*}} isDefinition: true // CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]] +// CHECK: distinct !DISubprogram(name: "c",{{.*}}, scope: ![[C:[0-9]+]],{{.*}}, line: 60,{{.*}} isDefinition: true +// CHECK: ![[C]] = !DINamespace(name: "C", // CHECK-GMLT: [[CU:![0-9]+]] = distinct !DICompileUnit( // CHECK-GMLT-SAME: emissionKind: LineTablesOnly, // CHECK-GMLT-NOT: imports: // CHECK-NOLIMIT: !DICompositeType(tag: DW_TAG_structure_type, name: "bar",{{.*}} line: 6, // CHECK-NOLIMIT-NOT: DIFlagFwdDecl // CHECK-NOLIMIT-SAME: ){{$}} Index: vendor/clang/dist/test/Modules/Inputs/module.map =================================================================== --- vendor/clang/dist/test/Modules/Inputs/module.map (revision 318415) +++ vendor/clang/dist/test/Modules/Inputs/module.map (revision 318416) @@ -1,443 +1,447 @@ module c_library [extern_c] { module inner { header "c-header.h" } } module cxx_library { header "cxx-header.h" requires cplusplus } module c_library_bad [extern_c] { header "c-header-bad.h" } module diamond_top { header "diamond_top.h" } module diamond_left { header "diamond_left.h" export diamond_top } module diamond_right { header "diamond_right.h" export diamond_top } module diamond_bottom { header "diamond_bottom.h" export * } module irgen { header "irgen.h" } module cxx_irgen_top { header "cxx-irgen-top.h" } module cxx_irgen_left { header "cxx-irgen-left.h" } module cxx_irgen_right { header "cxx-irgen-right.h" } module lookup_left_objc { header "lookup_left.h" } module lookup_right_objc { header "lookup_right.h" } module lookup_left_cxx { header "lookup_left.hpp" } module lookup_right_cxx { header "lookup_right.hpp" } module module_private_left { header "module_private_left.h" } module module_private_right { header "module_private_right.h" } module macros_top { header "macros_top.h" explicit module b { header "macros_top_b.h" } explicit module c { header "macros_top_c.h" } } module macros_left { header "macros_left.h" export * } module macros_right { header "macros_right.h" export * explicit module undef { header "macros_right_undef.h" } } module macros_bottom { header "macros_bottom.h" export * } module macros { header "macros.h" } module macros_other { header "macros_other.h" } module category_top { header "category_top.h" } module category_left { header "category_left.h" export category_top explicit module sub { header "category_left_sub.h" } } module category_right { header "category_right.h" export category_top explicit module sub { header "category_right_sub.h" } } module category_bottom { header "category_bottom.h" export category_left export category_right } module category_other { header "category_other.h" } module redeclarations_left { header "redeclarations_left.h" } module redeclarations_right { header "redeclarations_right.h" } module redecl_namespaces_left { header "redecl_namespaces_left.h" } module redecl_namespaces_right { header "redecl_namespaces_right.h" } module redecl_add_after_load_top { header "redecl-add-after-load-top.h" } module redecl_add_after_load_decls { header "redecl-add-after-load-decls.h" } module redecl_add_after_load { header "redecl-add-after-load.h" } module load_failure { header "load_failure.h" } module decldef { explicit module Decl { header "decl.h" } explicit module Decl2 { header "decl2.h" } explicit module Def { header "def.h" } } module redecl_merge_top { header "redecl-merge-top.h" explicit module Explicit { header "redecl-merge-top-explicit.h" } exclude header "nonexistent.h" } module redecl_merge_left { header "redecl-merge-left.h" export * } module redecl_merge_left_left { header "redecl-merge-left-left.h" export * } module redecl_merge_right { header "redecl-merge-right.h" export * } module redecl_merge_bottom { explicit module prefix { header "redecl-merge-bottom-prefix.h" } header "redecl-merge-bottom.h" export * } module namespaces_top { header "namespaces-top.h" export * } module namespaces_left { header "namespaces-left.h" export * } module namespaces_right { header "namespaces-right.h" export * } module templates_top { header "templates-top.h" export * } module templates_left { header "templates-left.h" export * } module templates_right { header "templates-right.h" export * } module MethodPoolA { header "MethodPoolA.h" explicit module Sub2 { header "MethodPoolASub2.h" } explicit module Sub { header "MethodPoolASub.h" } } module MethodPoolB { header "MethodPoolB.h" explicit module Sub2 { header "MethodPoolBSub2.h" } explicit module Sub { header "MethodPoolBSub.h" } } module import_decl { header "import-decl.h" } framework module * { exclude NotAModule } module linkage_merge_left { explicit module sub { header "linkage-merge-sub.h" } } module autolink { header "autolink.h" link "autolink" explicit module sub { header "autolink-sub.h" link "autolink_sub" } explicit module sub2 { header "autolink-sub2.h" link framework "autolink_framework" } explicit module sub3 { header "autolink-sub3.h" link "autolink_from_pch" } } module weird_objc { header "weird_objc.h" } module ignored_macros { header "ignored_macros.h" } module cxx_many_overloads { header "cxx-many-overloads.h" } module cxx_inline_namespace { header "cxx-inline-namespace.h" } module cxx_inline_namespace_b { header "cxx-inline-namespace-b.h" } module cxx_linkage_cache { header "cxx-linkage-cache.h" } module cxx_templates_common { header "cxx-templates-common.h" explicit module unimported { header "cxx-templates-unimported.h" } } module cxx_templates_a { header "cxx-templates-a.h" } module cxx_templates_b_impl { header "cxx-templates-b-impl.h" } module cxx_templates_b { header "cxx-templates-b.h" } module cxx_templates_c { header "cxx-templates-c.h" } module cxx_templates_d { header "cxx-templates-d.h" } module cxx_decls { module unimported { header "cxx-decls-unimported.h" } module imported { header "cxx-decls-imported.h" } } module cxx_decls_premerged { header "cxx-decls-premerged.h" } module cxx_decls_merged { header "cxx-decls-merged.h" } module config { header "config.h" config_macros [exhaustive] WANT_FOO, WANT_BAR } module diag_flags { header "diag_flags.h" } module diag_pragma { header "diag_pragma.h" } module pragma_pack { module set { header "pragma_pack_set.h" } module empty { header "empty.h" } } module dummy { header "dummy.h" } module builtin { header "builtin.h" explicit module sub { header "builtin_sub.h" } } module linkage_merge { explicit module foo { header "linkage-merge-foo.h" } explicit module bar { header "linkage-merge-bar.h" } } module incomplete_mod { header "incomplete_mod.h" } module warning { header "warning.h" } module warn_unused_local_typedef { header "warn-unused-local-typedef.h" } module using_decl { module a { header "using-decl-a.h" export * } module b { header "using-decl-b.h" export * } } module recursive_visibility_a1 { module inner { header "recursive_visibility_a1_inner.h" } } module recursive_visibility_a2 { module inner { module more_inner { header "recursive_visibility_a2_more_inner.h" } } } module recursive_visibility_b { header "recursive_visibility_b.h" export * } module recursive_visibility_c { header "recursive_visibility_c.h" } module recursive1 { header "recursive1.h" } module recursive2 { header "recursive2.h" } module crash { header "crash.h" } module DebugCXX { header "DebugCXX.h" } module DebugObjC { header "DebugObjC.h" } module ImportNameInDir { header "ImportNameInDir.h" export * } module RequiresWithMissingHeader { module HeaderBefore { header "RequiresWithMissingHeader-Missing1.h" requires missing } module HeaderAfter { requires missing header "RequiresWithMissingHeader-Missing2.h" } } module TargetFeatures { module arm { requires arm module aarch32 { requires aarch32 } module aarch64 { requires aarch64 } } module x86 { requires x86 module x86_32 { requires x86_32 } module x86_64 { requires x86_64 } } } module DebugSubmodules { module DebugSubmoduleA { header "DebugSubmoduleA.h" export * } module DebugSubmoduleB { header "DebugSubmoduleB.h" export * } } module ExtensionTestA { header "ExtensionTestA.h" } module TypedefTag { header "typedef-tag.h" explicit module Hidden { header "typedef-tag-hidden.h" } } module ElaboratedTypeStructs { module Empty {} module Structs { header "elaborated-type-structs.h" } } // We import a module, then declare a method with selector stringValue in // MethodPoolCombined1.h. In MethodPoolCombined2.h, we import another module // that also contains a method for selector stringValue. We make sure that // the method pool entry for stringValue in this module is complete. module MethodPoolCombined { header "MethodPoolCombined1.h" header "MethodPoolCombined2.h" } module MethodPoolString1 { header "MethodPoolString1.h" } module MethodPoolString2 { header "MethodPoolString2.h" } module Empty {} module MacroFabs1 { header "MacroFabs1.h" } module DiagOutOfDate { header "DiagOutOfDate.h" } module DebugNestedA { header "DebugNestedA.h" export * } module DebugNestedB { header "DebugNestedB.h" export * } + +module objcAtKeywordMissingEnd { + header "objcAtKeywordMissingEnd.h" +} Index: vendor/clang/dist/test/Modules/Inputs/objcAtKeywordMissingEnd.h =================================================================== --- vendor/clang/dist/test/Modules/Inputs/objcAtKeywordMissingEnd.h (nonexistent) +++ vendor/clang/dist/test/Modules/Inputs/objcAtKeywordMissingEnd.h (revision 318416) @@ -0,0 +1,3 @@ +@interface MissingEnd // expected-note {{class started here}} + +@ // expected-error {{expected an Objective-C directive after '@'}} expected-error {{missing '@end'}} Property changes on: vendor/clang/dist/test/Modules/Inputs/objcAtKeywordMissingEnd.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/clang/dist/test/Modules/Inputs/submodule-visibility/b.h =================================================================== --- vendor/clang/dist/test/Modules/Inputs/submodule-visibility/b.h (revision 318415) +++ vendor/clang/dist/test/Modules/Inputs/submodule-visibility/b.h (revision 318416) @@ -1,10 +1,14 @@ int m = n; #include "other.h" #include "c.h" #if defined(A) && !defined(ALLOW_NAME_LEAKAGE) -#error A is defined +#warning A is defined #endif #define B + +template void b_template() { + N::C::f(0); +} Index: vendor/clang/dist/test/Modules/Inputs/submodule-visibility/other.h =================================================================== --- vendor/clang/dist/test/Modules/Inputs/submodule-visibility/other.h (revision 318415) +++ vendor/clang/dist/test/Modules/Inputs/submodule-visibility/other.h (revision 318416) @@ -1 +1,10 @@ #include "c.h" + +#ifndef OTHER_H +#define OTHER_H +namespace N { + struct C { + template static void f(U) {} + }; +} +#endif Index: vendor/clang/dist/test/Modules/objc-at-keyword.m =================================================================== --- vendor/clang/dist/test/Modules/objc-at-keyword.m (nonexistent) +++ vendor/clang/dist/test/Modules/objc-at-keyword.m (revision 318416) @@ -0,0 +1,7 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify -x objective-c -fmodule-name=objcAtKeywordMissingEnd -emit-module %S/Inputs/module.map +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c -fmodule-name=Empty -emit-module %S/Inputs/module.map +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify -I %S/Inputs %s + +@interface X // expected-note {{class started here}} +#pragma clang module import Empty // expected-error {{missing '@end'}} Index: vendor/clang/dist/test/Modules/odr_hash.cpp =================================================================== --- vendor/clang/dist/test/Modules/odr_hash.cpp (revision 318415) +++ vendor/clang/dist/test/Modules/odr_hash.cpp (revision 318416) @@ -1,1121 +1,1352 @@ // Clear and create directories // RUN: rm -rf %t // RUN: mkdir %t // RUN: mkdir %t/cache // RUN: mkdir %t/Inputs // Build first header file // RUN: echo "#define FIRST" >> %t/Inputs/first.h // RUN: cat %s >> %t/Inputs/first.h // Build second header file // RUN: echo "#define SECOND" >> %t/Inputs/second.h // RUN: cat %s >> %t/Inputs/second.h // Build module map file // RUN: echo "module FirstModule {" >> %t/Inputs/module.map // RUN: echo " header \"first.h\"" >> %t/Inputs/module.map // RUN: echo "}" >> %t/Inputs/module.map // RUN: echo "module SecondModule {" >> %t/Inputs/module.map // RUN: echo " header \"second.h\"" >> %t/Inputs/module.map // RUN: echo "}" >> %t/Inputs/module.map // Run test // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -std=c++1z #if !defined(FIRST) && !defined(SECOND) #include "first.h" #include "second.h" #endif namespace AccessSpecifiers { #if defined(FIRST) struct S1 { }; #elif defined(SECOND) struct S1 { private: }; #else S1 s1; // expected-error@second.h:* {{'AccessSpecifiers::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}} // expected-note@first.h:* {{but in 'FirstModule' found end of class}} #endif #if defined(FIRST) struct S2 { public: }; #elif defined(SECOND) struct S2 { protected: }; #else S2 s2; // expected-error@second.h:* {{'AccessSpecifiers::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found protected access specifier}} // expected-note@first.h:* {{but in 'FirstModule' found public access specifier}} #endif } // namespace AccessSpecifiers namespace StaticAssert { #if defined(FIRST) struct S1 { static_assert(1 == 1, "First"); }; #elif defined(SECOND) struct S1 { static_assert(1 == 1, "Second"); }; #else S1 s1; // expected-error@second.h:* {{'StaticAssert::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with message}} // expected-note@first.h:* {{but in 'FirstModule' found static assert with different message}} #endif #if defined(FIRST) struct S2 { static_assert(2 == 2, "Message"); }; #elif defined(SECOND) struct S2 { static_assert(2 == 2); }; #else S2 s2; // expected-error@second.h:* {{'StaticAssert::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with no message}} // expected-note@first.h:* {{but in 'FirstModule' found static assert with message}} #endif #if defined(FIRST) struct S3 { static_assert(3 == 3, "Message"); }; #elif defined(SECOND) struct S3 { static_assert(3 != 4, "Message"); }; #else S3 s3; // expected-error@second.h:* {{'StaticAssert::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with condition}} // expected-note@first.h:* {{but in 'FirstModule' found static assert with different condition}} #endif #if defined(FIRST) struct S4 { static_assert(4 == 4, "Message"); }; #elif defined(SECOND) struct S4 { public: }; #else S4 s4; // expected-error@second.h:* {{'StaticAssert::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}} // expected-note@first.h:* {{but in 'FirstModule' found static assert}} #endif } namespace Field { #if defined(FIRST) struct S1 { int x; private: int y; }; #elif defined(SECOND) struct S1 { int x; int y; }; #else S1 s1; // expected-error@second.h:* {{'Field::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}} // expected-note@first.h:* {{but in 'FirstModule' found private access specifier}} #endif #if defined(FIRST) struct S2 { int x; int y; }; #elif defined(SECOND) struct S2 { int y; int x; }; #else S2 s2; // expected-error@second.h:* {{'Field::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'y'}} // expected-note@first.h:* {{but in 'FirstModule' found field 'x'}} #endif #if defined(FIRST) struct S3 { double x; }; #elif defined(SECOND) struct S3 { int x; }; #else S3 s3; // expected-error@first.h:* {{'Field::S3::x' from module 'FirstModule' is not present in definition of 'Field::S3' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'x' does not match}} #endif #if defined(FIRST) typedef int A; struct S4 { A x; }; struct S5 { A x; }; #elif defined(SECOND) typedef int B; struct S4 { B x; }; struct S5 { int x; }; #else S4 s4; // expected-error@second.h:* {{'Field::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'Field::B' (aka 'int')}} // expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'Field::A' (aka 'int')}} S5 s5; // expected-error@second.h:* {{'Field::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'int'}} // expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'Field::A' (aka 'int')}} #endif #if defined(FIRST) struct S6 { unsigned x; }; #elif defined(SECOND) struct S6 { unsigned x : 1; }; #else S6 s6; // expected-error@second.h:* {{'Field::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x'}} // expected-note@first.h:* {{but in 'FirstModule' found non-bitfield 'x'}} #endif #if defined(FIRST) struct S7 { unsigned x : 2; }; #elif defined(SECOND) struct S7 { unsigned x : 1; }; #else S7 s7; // expected-error@second.h:* {{'Field::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x' with one width expression}} // expected-note@first.h:* {{but in 'FirstModule' found bitfield 'x' with different width expression}} #endif #if defined(FIRST) struct S8 { unsigned x : 2; }; #elif defined(SECOND) struct S8 { unsigned x : 1 + 1; }; #else S8 s8; // expected-error@second.h:* {{'Field::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x' with one width expression}} // expected-note@first.h:* {{but in 'FirstModule' found bitfield 'x' with different width expression}} #endif #if defined(FIRST) struct S9 { mutable int x; }; #elif defined(SECOND) struct S9 { int x; }; #else S9 s9; // expected-error@second.h:* {{'Field::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found non-mutable field 'x'}} // expected-note@first.h:* {{but in 'FirstModule' found mutable field 'x'}} #endif #if defined(FIRST) struct S10 { unsigned x = 5; }; #elif defined(SECOND) struct S10 { unsigned x; }; #else S10 s10; // expected-error@second.h:* {{'Field::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with no initalizer}} // expected-note@first.h:* {{but in 'FirstModule' found field 'x' with an initializer}} #endif #if defined(FIRST) struct S11 { unsigned x = 5; }; #elif defined(SECOND) struct S11 { unsigned x = 7; }; #else S11 s11; // expected-error@second.h:* {{'Field::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with an initializer}} // expected-note@first.h:* {{but in 'FirstModule' found field 'x' with a different initializer}} #endif #if defined(FIRST) struct S12 { unsigned x[5]; }; #elif defined(SECOND) struct S12 { unsigned x[7]; }; #else S12 s12; // expected-error@first.h:* {{'Field::S12::x' from module 'FirstModule' is not present in definition of 'Field::S12' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'x' does not match}} #endif #if defined(FIRST) struct S13 { unsigned x[7]; }; #elif defined(SECOND) struct S13 { double x[7]; }; #else S13 s13; // expected-error@first.h:* {{'Field::S13::x' from module 'FirstModule' is not present in definition of 'Field::S13' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'x' does not match}} #endif } // namespace Field namespace Method { #if defined(FIRST) struct S1 { void A() {} }; #elif defined(SECOND) struct S1 { private: void A() {} }; #else S1 s1; // expected-error@second.h:* {{'Method::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}} // expected-note@first.h:* {{but in 'FirstModule' found method}} #endif #if defined(FIRST) struct S2 { void A() {} void B() {} }; #elif defined(SECOND) struct S2 { void B() {} void A() {} }; #else S2 s2; // expected-error@second.h:* {{'Method::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'B'}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A'}} #endif #if defined(FIRST) struct S3 { static void A() {} void A(int) {} }; #elif defined(SECOND) struct S3 { void A(int) {} static void A() {} }; #else S3 s3; // expected-error@second.h:* {{'Method::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not static}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' is static}} #endif #if defined(FIRST) struct S4 { virtual void A() {} void B() {} }; #elif defined(SECOND) struct S4 { void A() {} virtual void B() {} }; #else S4 s4; // expected-error@second.h:* {{'Method::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not virtual}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' is virtual}} #endif #if defined(FIRST) struct S5 { virtual void A() = 0; virtual void B() {}; }; #elif defined(SECOND) struct S5 { virtual void A() {} virtual void B() = 0; }; #else S5 *s5; // expected-error@second.h:* {{'Method::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is virtual}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' is pure virtual}} #endif #if defined(FIRST) struct S6 { inline void A() {} }; #elif defined(SECOND) struct S6 { void A() {} }; #else S6 s6; // expected-error@second.h:* {{'Method::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not inline}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' is inline}} #endif #if defined(FIRST) struct S7 { void A() volatile {} void A() {} }; #elif defined(SECOND) struct S7 { void A() {} void A() volatile {} }; #else S7 s7; // expected-error@second.h:* {{'Method::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not volatile}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' is volatile}} #endif #if defined(FIRST) struct S8 { void A() const {} void A() {} }; #elif defined(SECOND) struct S8 { void A() {} void A() const {} }; #else S8 s8; // expected-error@second.h:* {{'Method::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not const}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' is const}} #endif #if defined(FIRST) struct S9 { void A(int x) {} void A(int x, int y) {} }; #elif defined(SECOND) struct S9 { void A(int x, int y) {} void A(int x) {} }; #else S9 s9; // expected-error@second.h:* {{'Method::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' that has 2 parameters}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' that has 1 parameter}} #endif #if defined(FIRST) struct S10 { void A(int x) {} void A(float x) {} }; #elif defined(SECOND) struct S10 { void A(float x) {} void A(int x) {} }; #else S10 s10; // expected-error@second.h:* {{'Method::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter of type 'float'}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter of type 'int'}} #endif #if defined(FIRST) struct S11 { void A(int x) {} }; #elif defined(SECOND) struct S11 { void A(int y) {} }; #else S11 s11; // expected-error@second.h:* {{'Method::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter named 'y'}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter named 'x'}} #endif #if defined(FIRST) struct S12 { void A(int x) {} }; #elif defined(SECOND) struct S12 { void A(int x = 1) {} }; #else S12 s12; // TODO: This should produce an error. #endif #if defined(FIRST) struct S13 { void A(int x = 1 + 0) {} }; #elif defined(SECOND) struct S13 { void A(int x = 1) {} }; #else S13 s13; // TODO: This should produce an error. #endif #if defined(FIRST) struct S14 { void A(int x[2]) {} }; #elif defined(SECOND) struct S14 { void A(int x[3]) {} }; #else S14 s14; // expected-error@second.h:* {{'Method::S14' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter of type 'int *' decayed from 'int [3]'}} // expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter of type 'int *' decayed from 'int [2]'}} #endif } // namespace Method // Naive parsing of AST can lead to cycles in processing. Ensure // self-references don't trigger an endless cycles of AST node processing. namespace SelfReference { #if defined(FIRST) template